Move "async move" a few characters to the left in cx.spawn() (#26758)

Mikayla Maki created

This is the core change:
https://github.com/zed-industries/zed/pull/26758/files#diff-044302c0d57147af17e68a0009fee3e8dcdfb4f32c27a915e70cfa80e987f765R1052

TODO:
- [x] Use AsyncFn instead of Fn() -> Future in GPUI spawn methods
- [x] Implement it in the whole app
- [x] Implement it in the debugger 
- [x] Glance at the RPC crate, and see if those box future methods can
be switched over. Answer: It can't directly, as you can't make an
AsyncFn* into a trait object. There's ways around that, but they're all
more complex than just keeping the code as is.
- [ ] Fix platform specific code

Release Notes:

- N/A

Change summary

crates/activity_indicator/src/activity_indicator.rs              |  14 
crates/askpass/src/askpass.rs                                    |   4 
crates/assistant/src/assistant.rs                                |   6 
crates/assistant/src/assistant_panel.rs                          |  48 
crates/assistant/src/inline_assistant.rs                         | 392 -
crates/assistant/src/terminal_inline_assistant.rs                |  12 
crates/assistant2/src/active_thread.rs                           |  12 
crates/assistant2/src/assistant_panel.rs                         |  20 
crates/assistant2/src/buffer_codegen.rs                          | 390 -
crates/assistant2/src/context_picker.rs                          |  12 
crates/assistant2/src/context_picker/fetch_context_picker.rs     |   4 
crates/assistant2/src/context_picker/file_context_picker.rs      |  10 
crates/assistant2/src/context_picker/thread_context_picker.rs    |   8 
crates/assistant2/src/context_store.rs                           |  42 
crates/assistant2/src/context_strip.rs                           |   6 
crates/assistant2/src/inline_assistant.rs                        |  10 
crates/assistant2/src/message_editor.rs                          |   8 
crates/assistant2/src/terminal_codegen.rs                        |   8 
crates/assistant2/src/thread.rs                                  |  41 
crates/assistant2/src/thread_store.rs                            |  20 
crates/assistant_context_editor/src/context.rs                   |  45 
crates/assistant_context_editor/src/context_editor.rs            |  47 
crates/assistant_context_editor/src/context_history.rs           |   4 
crates/assistant_context_editor/src/context_store.rs             |  41 
crates/assistant_context_editor/src/slash_command.rs             |   2 
crates/assistant_context_editor/src/slash_command_picker.rs      |   4 
crates/assistant_eval/src/eval.rs                                |   8 
crates/assistant_eval/src/headless_assistant.rs                  |   2 
crates/assistant_eval/src/judge.rs                               |   2 
crates/assistant_eval/src/main.rs                                |   2 
crates/assistant_slash_commands/src/auto_command.rs              |   8 
crates/assistant_slash_commands/src/diagnostics_command.rs       |   6 
crates/assistant_slash_commands/src/file_command.rs              |   6 
crates/assistant_slash_commands/src/project_command.rs           |   4 
crates/assistant_slash_commands/src/search_command.rs            |   4 
crates/assistant_slash_commands/src/tab_command.rs               |   6 
crates/assistant_tools/src/bash_tool.rs                          |   2 
crates/assistant_tools/src/diagnostics_tool.rs                   |   4 
crates/assistant_tools/src/edit_files_tool.rs                    |  14 
crates/assistant_tools/src/read_file_tool.rs                     |   6 
crates/assistant_tools/src/regex_search_tool.rs                  |   4 
crates/auto_update/src/auto_update.rs                            |  12 
crates/auto_update_ui/src/auto_update_ui.rs                      |   6 
crates/buffer_diff/src/buffer_diff.rs                            |   4 
crates/call/src/cross_platform/mod.rs                            |  36 
crates/call/src/cross_platform/room.rs                           |  62 
crates/call/src/macos/mod.rs                                     |  46 
crates/call/src/macos/room.rs                                    |  79 
crates/channel/src/channel_buffer.rs                             |   6 
crates/channel/src/channel_chat.rs                               |  34 
crates/channel/src/channel_store.rs                              |  80 
crates/client/src/client.rs                                      |  92 
crates/client/src/test.rs                                        |   4 
crates/client/src/user.rs                                        |  65 
crates/collab/src/tests/channel_buffer_tests.rs                  |   2 
crates/collab/src/tests/integration_tests.rs                     |   8 
crates/collab/src/tests/test_server.rs                           |   6 
crates/collab_ui/src/channel_view.rs                             |  16 
crates/collab_ui/src/chat_panel.rs                               |  14 
crates/collab_ui/src/chat_panel/message_editor.rs                |  16 
crates/collab_ui/src/collab_panel.rs                             |  30 
crates/collab_ui/src/collab_panel/channel_modal.rs               |  24 
crates/collab_ui/src/collab_panel/contact_finder.rs              |   4 
crates/collab_ui/src/notification_panel.rs                       |  18 
crates/collab_ui/src/notifications/incoming_call_notification.rs |   6 
crates/command_palette/src/command_palette.rs                    |   4 
crates/component_preview/src/component_preview.rs                |   2 
crates/context_server/src/client.rs                              |  12 
crates/context_server/src/extension_context_server.rs            |  19 
crates/context_server/src/manager.rs                             |  30 
crates/context_server/src/transport/stdio_transport.rs           |   6 
crates/copilot/src/copilot.rs                                    |  27 
crates/copilot/src/copilot_chat.rs                               |   2 
crates/copilot/src/copilot_completion_provider.rs                |  12 
crates/copilot/src/sign_in.rs                                    |   4 
crates/dap/src/transport.rs                                      |   2 
crates/debugger_tools/src/dap_log.rs                             |  12 
crates/debugger_ui/src/attach_modal.rs                           |   6 
crates/debugger_ui/src/debugger_panel.rs                         |   8 
crates/debugger_ui/src/session/running/console.rs                |   6 
crates/debugger_ui/src/session/running/module_list.rs            |   8 
crates/debugger_ui/src/session/running/stack_frame_list.rs       |  12 
crates/debugger_ui/src/session/starting.rs                       |   4 
crates/debugger_ui/src/tests.rs                                  |  12 
crates/diagnostics/src/diagnostics.rs                            |  35 
crates/diagnostics/src/items.rs                                  |   4 
crates/editor/src/blink_manager.rs                               |   8 
crates/editor/src/clangd_ext.rs                                  |   4 
crates/editor/src/code_context_menus.rs                          |   4 
crates/editor/src/display_map/wrap_map.rs                        |   8 
crates/editor/src/editor.rs                                      | 295 
crates/editor/src/editor_tests.rs                                |   1 
crates/editor/src/element.rs                                     |   8 
crates/editor/src/git/blame.rs                                   |   8 
crates/editor/src/hover_links.rs                                 |  13 
crates/editor/src/hover_popover.rs                               |  29 
crates/editor/src/indent_guides.rs                               |  19 
crates/editor/src/inlay_hint_cache.rs                            |  34 
crates/editor/src/items.rs                                       |  54 
crates/editor/src/jsx_tag_auto_close.rs                          |  16 
crates/editor/src/linked_editing_ranges.rs                       |   8 
crates/editor/src/proposed_changes_editor.rs                     |   4 
crates/editor/src/rust_analyzer_ext.rs                           |  10 
crates/editor/src/scroll.rs                                      |   8 
crates/editor/src/scroll/actions.rs                              |   4 
crates/editor/src/signature_help.rs                              |   4 
crates/evals/src/eval.rs                                         |   4 
crates/extension_host/src/extension_host.rs                      | 103 
crates/extension_host/src/headless_host.rs                       |  19 
crates/extension_host/src/wasm_host.rs                           |   4 
crates/extensions_ui/src/extension_version_selector.rs           |   4 
crates/extensions_ui/src/extensions_ui.rs                        |  24 
crates/feature_flags/src/feature_flags.rs                        |   2 
crates/feedback/src/feedback.rs                                  |   6 
crates/feedback/src/feedback_modal.rs                            |  51 
crates/file_finder/src/file_finder.rs                            |  26 
crates/file_finder/src/new_path_prompt.rs                        |   8 
crates/file_finder/src/open_path_prompt.rs                       |  10 
crates/git/src/fake_repository.rs                                |   2 
crates/git/src/repository.rs                                     |   4 
crates/git_ui/src/branch_picker.rs                               |  16 
crates/git_ui/src/git_panel.rs                                   | 145 
crates/git_ui/src/onboarding.rs                                  |  14 
crates/git_ui/src/picker_prompt.rs                               |  10 
crates/git_ui/src/project_diff.rs                                |  18 
crates/git_ui/src/repository_selector.rs                         |   4 
crates/go_to_line/src/cursor_position.rs                         |   8 
crates/gpui/examples/opacity.rs                                  |  32 
crates/gpui/examples/window.rs                                   |   2 
crates/gpui/src/app.rs                                           |   8 
crates/gpui/src/app/async_context.rs                             |  31 
crates/gpui/src/app/context.rs                                   |  29 
crates/gpui/src/elements/div.rs                                  |   4 
crates/gpui/src/elements/img.rs                                  |   2 
crates/gpui/src/window.rs                                        |  15 
crates/image_viewer/src/image_viewer.rs                          |  14 
crates/inline_completion_button/src/inline_completion_button.rs  |  10 
crates/journal/src/journal.rs                                    |   8 
crates/language/src/buffer.rs                                    |  16 
crates/language/src/language_registry.rs                         |   4 
crates/language_model_selector/src/language_model_selector.rs    |   6 
crates/language_models/src/provider/anthropic.rs                 |  28 
crates/language_models/src/provider/bedrock.rs                   |  26 
crates/language_models/src/provider/cloud.rs                     |  16 
crates/language_models/src/provider/copilot_chat.rs              |   5 
crates/language_models/src/provider/deepseek.rs                  |  30 
crates/language_models/src/provider/google.rs                    |  28 
crates/language_models/src/provider/lmstudio.rs                  |  14 
crates/language_models/src/provider/mistral.rs                   |  28 
crates/language_models/src/provider/ollama.rs                    |  14 
crates/language_models/src/provider/open_ai.rs                   |  28 
crates/language_selector/src/language_selector.rs                |   8 
crates/language_tools/src/lsp_log.rs                             |  12 
crates/languages/src/go.rs                                       |   2 
crates/languages/src/lib.rs                                      |   2 
crates/languages/src/python.rs                                   |   4 
crates/livekit_client/examples/test_app.rs                       |  12 
crates/livekit_client/src/remote_video_track_view.rs             |   6 
crates/livekit_client_macos/examples/test_app_macos.rs           |   2 
crates/lsp/src/lsp.rs                                            |  41 
crates/markdown/src/markdown.rs                                  |   7 
crates/markdown_preview/src/markdown_preview_view.rs             |   6 
crates/multi_buffer/src/multi_buffer.rs                          |   4 
crates/notifications/src/notification_store.rs                   |  30 
crates/outline_panel/src/outline_panel.rs                        |  58 
crates/picker/src/picker.rs                                      |  10 
crates/prettier/src/prettier.rs                                  |   4 
crates/project/src/buffer_store.rs                               |  88 
crates/project/src/connection_manager.rs                         |  18 
crates/project/src/debounced_delay.rs                            |   4 
crates/project/src/debugger/breakpoint_store.rs                  |  12 
crates/project/src/debugger/dap_store.rs                         |  22 
crates/project/src/debugger/session.rs                           |  53 
crates/project/src/environment.rs                                |   6 
crates/project/src/git.rs                                        |  60 
crates/project/src/image_store.rs                                |  20 
crates/project/src/lsp_command.rs                                |   4 
crates/project/src/lsp_store.rs                                  | 384 -
crates/project/src/lsp_store/clangd_ext.rs                       |   4 
crates/project/src/lsp_store/rust_analyzer_ext.rs                |   4 
crates/project/src/prettier_store.rs                             |  50 
crates/project/src/project.rs                                    | 123 
crates/project/src/project_settings.rs                           |   2 
crates/project/src/task_store.rs                                 |  14 
crates/project/src/terminals.rs                                  |  14 
crates/project/src/toolchain_store.rs                            |  14 
crates/project/src/worktree_store.rs                             |  20 
crates/project/src/yarn.rs                                       |   8 
crates/project_panel/src/project_panel.rs                        |  89 
crates/project_symbols/src/project_symbols.rs                    |   8 
crates/prompt_library/src/prompt_library.rs                      |  36 
crates/recent_projects/src/disconnected_overlay.rs               |   4 
crates/recent_projects/src/recent_projects.rs                    |  18 
crates/recent_projects/src/remote_servers.rs                     |  34 
crates/recent_projects/src/ssh_connections.rs                    |   8 
crates/remote/src/ssh_session.rs                                 |  51 
crates/remote_server/src/headless_project.rs                     |   6 
crates/remote_server/src/unix.rs                                 |   4 
crates/repl/src/kernels/native_kernel.rs                         |  18 
crates/repl/src/kernels/remote_kernels.rs                        |   8 
crates/repl/src/notebook/cell.rs                                 |   8 
crates/repl/src/notebook/notebook_ui.rs                          |  10 
crates/repl/src/outputs/markdown.rs                              |  22 
crates/repl/src/repl_store.rs                                    |  10 
crates/repl/src/session.rs                                       |  18 
crates/reqwest_client/examples/client.rs                         |   2 
crates/scripting_tool/src/scripting_session.rs                   |  36 
crates/search/src/buffer_search.rs                               |  16 
crates/search/src/project_search.rs                              |  14 
crates/semantic_index/examples/index.rs                          |   8 
crates/semantic_index/src/embedding_index.rs                     |   2 
crates/semantic_index/src/project_index.rs                       |  35 
crates/semantic_index/src/project_index_debug_view.rs            |  10 
crates/semantic_index/src/summary_index.rs                       |   6 
crates/semantic_index/src/worktree_index.rs                      |  12 
crates/session/src/session.rs                                    |  16 
crates/settings/src/settings_store.rs                            |   2 
crates/snippet_provider/src/lib.rs                               |   4 
crates/snippets_ui/src/snippets_ui.rs                            |   8 
crates/storybook/src/storybook.rs                                |   2 
crates/supermaven/src/supermaven.rs                              |  22 
crates/supermaven/src/supermaven_completion_provider.rs          |   4 
crates/tasks_ui/src/modal.rs                                     |  60 
crates/tasks_ui/src/tasks_ui.rs                                  |  18 
crates/terminal/src/terminal.rs                                  |   8 
crates/terminal_view/src/persistence.rs                          |  12 
crates/terminal_view/src/terminal_panel.rs                       |  60 
crates/terminal_view/src/terminal_view.rs                        |  36 
crates/theme_selector/src/icon_theme_selector.rs                 |   4 
crates/theme_selector/src/theme_selector.rs                      |   4 
crates/title_bar/src/title_bar.rs                                |   4 
crates/toolchain_selector/src/active_toolchain.rs                |  30 
crates/toolchain_selector/src/toolchain_selector.rs              |  22 
crates/ui/src/components/context_menu.rs                         |   2 
crates/vim/src/command.rs                                        |  12 
crates/vim/src/normal/mark.rs                                    |   4 
crates/vim/src/normal/search.rs                                  |  16 
crates/vim/src/normal/yank.rs                                    |   4 
crates/vim/src/state.rs                                          |   6 
crates/welcome/src/base_keymap_picker.rs                         |   4 
crates/welcome/src/welcome.rs                                    |   2 
crates/workspace/src/item.rs                                     |   4 
crates/workspace/src/notifications.rs                            |  21 
crates/workspace/src/pane.rs                                     |  36 
crates/workspace/src/searchable.rs                               |   2 
crates/workspace/src/shared_screen/macos.rs                      |   6 
crates/workspace/src/toast_layer.rs                              |   4 
crates/workspace/src/workspace.rs                                | 284 
crates/worktree/src/worktree.rs                                  |  85 
crates/zed/src/main.rs                                           |  38 
crates/zed/src/zed.rs                                            | 100 
crates/zed/src/zed/migrate.rs                                    |  20 
crates/zed/src/zed/open_listener.rs                              |   6 
crates/zeta/src/onboarding_banner.rs                             |  14 
crates/zeta/src/onboarding_modal.rs                              |  10 
crates/zeta/src/zeta.rs                                          |  20 
256 files changed, 3,080 insertions(+), 3,165 deletions(-)

Detailed changes

crates/activity_indicator/src/activity_indicator.rs 🔗

@@ -63,9 +63,9 @@ impl ActivityIndicator {
         let auto_updater = AutoUpdater::get(cx);
         let this = cx.new(|cx| {
             let mut status_events = languages.language_server_binary_statuses();
-            cx.spawn(|this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 while let Some((name, status)) = status_events.next().await {
-                    this.update(&mut cx, |this: &mut ActivityIndicator, cx| {
+                    this.update(cx, |this: &mut ActivityIndicator, cx| {
                         this.statuses.retain(|s| s.name != name);
                         this.statuses.push(ServerStatus { name, status });
                         cx.notify();
@@ -76,9 +76,9 @@ impl ActivityIndicator {
             .detach();
 
             let mut status_events = languages.dap_server_binary_statuses();
-            cx.spawn(|this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 while let Some((name, status)) = status_events.next().await {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.statuses.retain(|s| s.name != name);
                         this.statuses.push(ServerStatus { name, status });
                         cx.notify();
@@ -123,9 +123,9 @@ impl ActivityIndicator {
                 let project = project.clone();
                 let error = error.clone();
                 let server_name = server_name.clone();
-                cx.spawn_in(window, |workspace, mut cx| async move {
+                cx.spawn_in(window, async move |workspace, cx| {
                     let buffer = create_buffer.await?;
-                    buffer.update(&mut cx, |buffer, cx| {
+                    buffer.update(cx, |buffer, cx| {
                         buffer.edit(
                             [(
                                 0..0,
@@ -136,7 +136,7 @@ impl ActivityIndicator {
                         );
                         buffer.set_capability(language::Capability::ReadOnly, cx);
                     })?;
-                    workspace.update_in(&mut cx, |workspace, window, cx| {
+                    workspace.update_in(cx, |workspace, window, cx| {
                         workspace.add_item_to_active_pane(
                             Box::new(cx.new(|cx| {
                                 Editor::for_buffer(buffer, Some(project.clone()), window, cx)

crates/askpass/src/askpass.rs 🔗

@@ -34,9 +34,9 @@ impl AskPassDelegate {
         password_prompt: impl Fn(String, oneshot::Sender<String>, &mut AsyncApp) + Send + Sync + 'static,
     ) -> Self {
         let (tx, mut rx) = mpsc::unbounded::<(String, oneshot::Sender<String>)>();
-        let task = cx.spawn(|mut cx| async move {
+        let task = cx.spawn(async move |cx: &mut AsyncApp| {
             while let Some((prompt, channel)) = rx.next().await {
-                password_prompt(prompt, channel, &mut cx);
+                password_prompt(prompt, channel, cx);
             }
         });
         Self { tx, _task: task }

crates/assistant/src/assistant.rs 🔗

@@ -98,9 +98,9 @@ pub fn init(
     AssistantSettings::register(cx);
     SlashCommandSettings::register(cx);
 
-    cx.spawn(|mut cx| {
+    cx.spawn({
         let client = client.clone();
-        async move {
+        async move |cx| {
             let is_search_slash_command_enabled = cx
                 .update(|cx| cx.wait_for_flag::<SearchSlashCommandFeatureFlag>())?
                 .await;
@@ -116,7 +116,7 @@ pub fn init(
             let semantic_index = SemanticDb::new(
                 paths::embeddings_dir().join("semantic-index-db.0.mdb"),
                 Arc::new(embedding_provider),
-                &mut cx,
+                cx,
             )
             .await?;
 

crates/assistant/src/assistant_panel.rs 🔗

@@ -98,16 +98,16 @@ impl AssistantPanel {
         prompt_builder: Arc<PromptBuilder>,
         cx: AsyncWindowContext,
     ) -> Task<Result<Entity<Self>>> {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let slash_commands = Arc::new(SlashCommandWorkingSet::default());
             let context_store = workspace
-                .update(&mut cx, |workspace, cx| {
+                .update(cx, |workspace, cx| {
                     let project = workspace.project().clone();
                     ContextStore::new(project, prompt_builder.clone(), slash_commands, cx)
                 })?
                 .await?;
 
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 // TODO: deserialize state.
                 cx.new(|cx| Self::new(workspace, context_store, window, cx))
             })
@@ -357,9 +357,9 @@ impl AssistantPanel {
     ) -> Task<()> {
         let mut status_rx = client.status();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             while let Some(status) = status_rx.next().await {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     if this.client_status.is_none()
                         || this
                             .client_status
@@ -371,7 +371,7 @@ impl AssistantPanel {
                 })
                 .log_err();
             }
-            this.update(&mut cx, |this, _cx| this.watch_client_status = None)
+            this.update(cx, |this, _cx| this.watch_client_status = None)
                 .log_err();
         })
     }
@@ -576,11 +576,11 @@ impl AssistantPanel {
         if self.authenticate_provider_task.is_none() {
             self.authenticate_provider_task = Some((
                 provider.id(),
-                cx.spawn_in(window, |this, mut cx| async move {
+                cx.spawn_in(window, async move |this, cx| {
                     if let Some(future) = load_credentials {
                         let _ = future.await;
                     }
-                    this.update(&mut cx, |this, _cx| {
+                    this.update(cx, |this, _cx| {
                         this.authenticate_provider_task = None;
                     })
                     .log_err();
@@ -641,9 +641,9 @@ impl AssistantPanel {
             }
         } else {
             let assistant_panel = assistant_panel.downgrade();
-            cx.spawn_in(window, |workspace, mut cx| async move {
+            cx.spawn_in(window, async move |workspace, cx| {
                 let Some(task) =
-                    assistant_panel.update(&mut cx, |assistant, cx| assistant.authenticate(cx))?
+                    assistant_panel.update(cx, |assistant, cx| assistant.authenticate(cx))?
                 else {
                     let answer = cx
                         .prompt(
@@ -665,7 +665,7 @@ impl AssistantPanel {
                     return Ok(());
                 };
                 task.await?;
-                if assistant_panel.update(&mut cx, |panel, cx| panel.is_authenticated(cx))? {
+                if assistant_panel.update(cx, |panel, cx| panel.is_authenticated(cx))? {
                     cx.update(|window, cx| match inline_assist_target {
                         InlineAssistTarget::Editor(active_editor, include_context) => {
                             let assistant_panel = if include_context {
@@ -698,7 +698,7 @@ impl AssistantPanel {
                         }
                     })?
                 } else {
-                    workspace.update_in(&mut cx, |workspace, window, cx| {
+                    workspace.update_in(cx, |workspace, window, cx| {
                         workspace.focus_panel::<AssistantPanel>(window, cx)
                     })?;
                 }
@@ -791,10 +791,10 @@ impl AssistantPanel {
                 .context_store
                 .update(cx, |store, cx| store.create_remote_context(cx));
 
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 let context = task.await?;
 
-                this.update_in(&mut cx, |this, window, cx| {
+                this.update_in(cx, |this, window, cx| {
                     let workspace = this.workspace.clone();
                     let project = this.project.clone();
                     let lsp_adapter_delegate =
@@ -847,9 +847,9 @@ impl AssistantPanel {
 
             self.show_context(editor.clone(), window, cx);
             let workspace = self.workspace.clone();
-            cx.spawn_in(window, move |_, mut cx| async move {
+            cx.spawn_in(window, async move |_, cx| {
                 workspace
-                    .update_in(&mut cx, |workspace, window, cx| {
+                    .update_in(cx, |workspace, window, cx| {
                         workspace.focus_panel::<AssistantPanel>(window, cx);
                     })
                     .ok();
@@ -1069,8 +1069,8 @@ impl AssistantPanel {
                 .filter(|editor| editor.read(cx).context().read(cx).path() == Some(&path))
         });
         if let Some(existing_context) = existing_context {
-            return cx.spawn_in(window, |this, mut cx| async move {
-                this.update_in(&mut cx, |this, window, cx| {
+            return cx.spawn_in(window, async move |this, cx| {
+                this.update_in(cx, |this, window, cx| {
                     this.show_context(existing_context, window, cx)
                 })
             });
@@ -1085,9 +1085,9 @@ impl AssistantPanel {
 
         let lsp_adapter_delegate = make_lsp_adapter_delegate(&project, cx).log_err().flatten();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let context = context.await?;
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 let editor = cx.new(|cx| {
                     ContextEditor::for_context(
                         context,
@@ -1117,8 +1117,8 @@ impl AssistantPanel {
                 .filter(|editor| *editor.read(cx).context().read(cx).id() == id)
         });
         if let Some(existing_context) = existing_context {
-            return cx.spawn_in(window, |this, mut cx| async move {
-                this.update_in(&mut cx, |this, window, cx| {
+            return cx.spawn_in(window, async move |this, cx| {
+                this.update_in(cx, |this, window, cx| {
                     this.show_context(existing_context.clone(), window, cx)
                 })?;
                 Ok(existing_context)
@@ -1134,9 +1134,9 @@ impl AssistantPanel {
             .log_err()
             .flatten();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let context = context.await?;
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 let editor = cx.new(|cx| {
                     ContextEditor::for_context(
                         context,

crates/assistant/src/inline_assistant.rs 🔗

@@ -1311,9 +1311,9 @@ impl EditorInlineAssists {
             assist_ids: Vec::new(),
             scroll_lock: None,
             highlight_updates: highlight_updates_tx,
-            _update_highlights: cx.spawn(|cx| {
+            _update_highlights: cx.spawn({
                 let editor = editor.downgrade();
-                async move {
+                async move |cx| {
                     while let Ok(()) = highlight_updates_rx.changed().await {
                         let editor = editor.upgrade().context("editor was dropped")?;
                         cx.update_global(|assistant: &mut InlineAssistant, cx| {
@@ -1850,7 +1850,7 @@ impl PromptEditor {
 
     fn count_tokens(&mut self, cx: &mut Context<Self>) {
         let assist_id = self.id;
-        self.pending_token_count = cx.spawn(|this, mut cx| async move {
+        self.pending_token_count = cx.spawn(async move |this, cx| {
             cx.background_executor().timer(Duration::from_secs(1)).await;
             let token_count = cx
                 .update_global(|inline_assistant: &mut InlineAssistant, cx| {
@@ -1862,7 +1862,7 @@ impl PromptEditor {
                 })??
                 .await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.token_counts = Some(token_count);
                 cx.notify();
             })
@@ -2882,7 +2882,7 @@ impl CodegenAlternative {
                 let request = self.build_request(user_prompt, assistant_panel_context, cx)?;
                 self.request = Some(request.clone());
 
-                cx.spawn(|_, cx| async move { model.stream_completion_text(request, &cx).await })
+                cx.spawn(async move |_, cx| model.stream_completion_text(request, &cx).await)
                     .boxed_local()
             };
         self.handle_stream(telemetry_id, provider_id.to_string(), api_key, stream, cx);
@@ -2999,213 +2999,207 @@ impl CodegenAlternative {
         let completion = Arc::new(Mutex::new(String::new()));
         let completion_clone = completion.clone();
 
-        self.generation = cx.spawn(|codegen, mut cx| {
-            async move {
-                let stream = stream.await;
-                let message_id = stream
-                    .as_ref()
-                    .ok()
-                    .and_then(|stream| stream.message_id.clone());
-                let generate = async {
-                    let (mut diff_tx, mut diff_rx) = mpsc::channel(1);
-                    let executor = cx.background_executor().clone();
-                    let message_id = message_id.clone();
-                    let line_based_stream_diff: Task<anyhow::Result<()>> =
-                        cx.background_spawn(async move {
-                            let mut response_latency = None;
-                            let request_start = Instant::now();
-                            let diff = async {
-                                let chunks = StripInvalidSpans::new(stream?.stream);
-                                futures::pin_mut!(chunks);
-                                let mut diff = StreamingDiff::new(selected_text.to_string());
-                                let mut line_diff = LineDiff::default();
-
-                                let mut new_text = String::new();
-                                let mut base_indent = None;
-                                let mut line_indent = None;
-                                let mut first_line = true;
-
-                                while let Some(chunk) = chunks.next().await {
-                                    if response_latency.is_none() {
-                                        response_latency = Some(request_start.elapsed());
-                                    }
-                                    let chunk = chunk?;
-                                    completion_clone.lock().push_str(&chunk);
-
-                                    let mut lines = chunk.split('\n').peekable();
-                                    while let Some(line) = lines.next() {
-                                        new_text.push_str(line);
-                                        if line_indent.is_none() {
-                                            if let Some(non_whitespace_ch_ix) =
-                                                new_text.find(|ch: char| !ch.is_whitespace())
-                                            {
-                                                line_indent = Some(non_whitespace_ch_ix);
-                                                base_indent = base_indent.or(line_indent);
-
-                                                let line_indent = line_indent.unwrap();
-                                                let base_indent = base_indent.unwrap();
-                                                let indent_delta =
-                                                    line_indent as i32 - base_indent as i32;
-                                                let mut corrected_indent_len = cmp::max(
-                                                    0,
-                                                    suggested_line_indent.len as i32 + indent_delta,
-                                                )
-                                                    as usize;
-                                                if first_line {
-                                                    corrected_indent_len = corrected_indent_len
-                                                        .saturating_sub(
-                                                            selection_start.column as usize,
-                                                        );
-                                                }
-
-                                                let indent_char = suggested_line_indent.char();
-                                                let mut indent_buffer = [0; 4];
-                                                let indent_str =
-                                                    indent_char.encode_utf8(&mut indent_buffer);
-                                                new_text.replace_range(
-                                                    ..line_indent,
-                                                    &indent_str.repeat(corrected_indent_len),
-                                                );
+        self.generation = cx.spawn(async move |codegen, cx| {
+            let stream = stream.await;
+            let message_id = stream
+                .as_ref()
+                .ok()
+                .and_then(|stream| stream.message_id.clone());
+            let generate = async {
+                let (mut diff_tx, mut diff_rx) = mpsc::channel(1);
+                let executor = cx.background_executor().clone();
+                let message_id = message_id.clone();
+                let line_based_stream_diff: Task<anyhow::Result<()>> =
+                    cx.background_spawn(async move {
+                        let mut response_latency = None;
+                        let request_start = Instant::now();
+                        let diff = async {
+                            let chunks = StripInvalidSpans::new(stream?.stream);
+                            futures::pin_mut!(chunks);
+                            let mut diff = StreamingDiff::new(selected_text.to_string());
+                            let mut line_diff = LineDiff::default();
+
+                            let mut new_text = String::new();
+                            let mut base_indent = None;
+                            let mut line_indent = None;
+                            let mut first_line = true;
+
+                            while let Some(chunk) = chunks.next().await {
+                                if response_latency.is_none() {
+                                    response_latency = Some(request_start.elapsed());
+                                }
+                                let chunk = chunk?;
+                                completion_clone.lock().push_str(&chunk);
+
+                                let mut lines = chunk.split('\n').peekable();
+                                while let Some(line) = lines.next() {
+                                    new_text.push_str(line);
+                                    if line_indent.is_none() {
+                                        if let Some(non_whitespace_ch_ix) =
+                                            new_text.find(|ch: char| !ch.is_whitespace())
+                                        {
+                                            line_indent = Some(non_whitespace_ch_ix);
+                                            base_indent = base_indent.or(line_indent);
+
+                                            let line_indent = line_indent.unwrap();
+                                            let base_indent = base_indent.unwrap();
+                                            let indent_delta =
+                                                line_indent as i32 - base_indent as i32;
+                                            let mut corrected_indent_len = cmp::max(
+                                                0,
+                                                suggested_line_indent.len as i32 + indent_delta,
+                                            )
+                                                as usize;
+                                            if first_line {
+                                                corrected_indent_len = corrected_indent_len
+                                                    .saturating_sub(
+                                                        selection_start.column as usize,
+                                                    );
                                             }
-                                        }
 
-                                        if line_indent.is_some() {
-                                            let char_ops = diff.push_new(&new_text);
-                                            line_diff
-                                                .push_char_operations(&char_ops, &selected_text);
-                                            diff_tx
-                                                .send((char_ops, line_diff.line_operations()))
-                                                .await?;
-                                            new_text.clear();
+                                            let indent_char = suggested_line_indent.char();
+                                            let mut indent_buffer = [0; 4];
+                                            let indent_str =
+                                                indent_char.encode_utf8(&mut indent_buffer);
+                                            new_text.replace_range(
+                                                ..line_indent,
+                                                &indent_str.repeat(corrected_indent_len),
+                                            );
                                         }
+                                    }
 
-                                        if lines.peek().is_some() {
-                                            let char_ops = diff.push_new("\n");
-                                            line_diff
-                                                .push_char_operations(&char_ops, &selected_text);
-                                            diff_tx
-                                                .send((char_ops, line_diff.line_operations()))
-                                                .await?;
-                                            if line_indent.is_none() {
-                                                // Don't write out the leading indentation in empty lines on the next line
-                                                // This is the case where the above if statement didn't clear the buffer
-                                                new_text.clear();
-                                            }
-                                            line_indent = None;
-                                            first_line = false;
+                                    if line_indent.is_some() {
+                                        let char_ops = diff.push_new(&new_text);
+                                        line_diff.push_char_operations(&char_ops, &selected_text);
+                                        diff_tx
+                                            .send((char_ops, line_diff.line_operations()))
+                                            .await?;
+                                        new_text.clear();
+                                    }
+
+                                    if lines.peek().is_some() {
+                                        let char_ops = diff.push_new("\n");
+                                        line_diff.push_char_operations(&char_ops, &selected_text);
+                                        diff_tx
+                                            .send((char_ops, line_diff.line_operations()))
+                                            .await?;
+                                        if line_indent.is_none() {
+                                            // Don't write out the leading indentation in empty lines on the next line
+                                            // This is the case where the above if statement didn't clear the buffer
+                                            new_text.clear();
                                         }
+                                        line_indent = None;
+                                        first_line = false;
                                     }
                                 }
+                            }
 
-                                let mut char_ops = diff.push_new(&new_text);
-                                char_ops.extend(diff.finish());
-                                line_diff.push_char_operations(&char_ops, &selected_text);
-                                line_diff.finish(&selected_text);
-                                diff_tx
-                                    .send((char_ops, line_diff.line_operations()))
-                                    .await?;
+                            let mut char_ops = diff.push_new(&new_text);
+                            char_ops.extend(diff.finish());
+                            line_diff.push_char_operations(&char_ops, &selected_text);
+                            line_diff.finish(&selected_text);
+                            diff_tx
+                                .send((char_ops, line_diff.line_operations()))
+                                .await?;
 
-                                anyhow::Ok(())
-                            };
+                            anyhow::Ok(())
+                        };
 
-                            let result = diff.await;
-
-                            let error_message =
-                                result.as_ref().err().map(|error| error.to_string());
-                            report_assistant_event(
-                                AssistantEvent {
-                                    conversation_id: None,
-                                    message_id,
-                                    kind: AssistantKind::Inline,
-                                    phase: AssistantPhase::Response,
-                                    model: model_telemetry_id,
-                                    model_provider: model_provider_id.to_string(),
-                                    response_latency,
-                                    error_message,
-                                    language_name: language_name.map(|name| name.to_proto()),
-                                },
-                                telemetry,
-                                http_client,
-                                model_api_key,
-                                &executor,
-                            );
-
-                            result?;
-                            Ok(())
-                        });
+                        let result = diff.await;
+
+                        let error_message = result.as_ref().err().map(|error| error.to_string());
+                        report_assistant_event(
+                            AssistantEvent {
+                                conversation_id: None,
+                                message_id,
+                                kind: AssistantKind::Inline,
+                                phase: AssistantPhase::Response,
+                                model: model_telemetry_id,
+                                model_provider: model_provider_id.to_string(),
+                                response_latency,
+                                error_message,
+                                language_name: language_name.map(|name| name.to_proto()),
+                            },
+                            telemetry,
+                            http_client,
+                            model_api_key,
+                            &executor,
+                        );
 
-                    while let Some((char_ops, line_ops)) = diff_rx.next().await {
-                        codegen.update(&mut cx, |codegen, cx| {
-                            codegen.last_equal_ranges.clear();
+                        result?;
+                        Ok(())
+                    });
 
-                            let edits = char_ops
-                                .into_iter()
-                                .filter_map(|operation| match operation {
-                                    CharOperation::Insert { text } => {
-                                        let edit_start = snapshot.anchor_after(edit_start);
-                                        Some((edit_start..edit_start, text))
-                                    }
-                                    CharOperation::Delete { bytes } => {
-                                        let edit_end = edit_start + bytes;
-                                        let edit_range = snapshot.anchor_after(edit_start)
-                                            ..snapshot.anchor_before(edit_end);
-                                        edit_start = edit_end;
-                                        Some((edit_range, String::new()))
-                                    }
-                                    CharOperation::Keep { bytes } => {
-                                        let edit_end = edit_start + bytes;
-                                        let edit_range = snapshot.anchor_after(edit_start)
-                                            ..snapshot.anchor_before(edit_end);
-                                        edit_start = edit_end;
-                                        codegen.last_equal_ranges.push(edit_range);
-                                        None
-                                    }
-                                })
-                                .collect::<Vec<_>>();
+                while let Some((char_ops, line_ops)) = diff_rx.next().await {
+                    codegen.update(cx, |codegen, cx| {
+                        codegen.last_equal_ranges.clear();
 
-                            if codegen.active {
-                                codegen.apply_edits(edits.iter().cloned(), cx);
-                                codegen.reapply_line_based_diff(line_ops.iter().cloned(), cx);
-                            }
-                            codegen.edits.extend(edits);
-                            codegen.line_operations = line_ops;
-                            codegen.edit_position = Some(snapshot.anchor_after(edit_start));
+                        let edits = char_ops
+                            .into_iter()
+                            .filter_map(|operation| match operation {
+                                CharOperation::Insert { text } => {
+                                    let edit_start = snapshot.anchor_after(edit_start);
+                                    Some((edit_start..edit_start, text))
+                                }
+                                CharOperation::Delete { bytes } => {
+                                    let edit_end = edit_start + bytes;
+                                    let edit_range = snapshot.anchor_after(edit_start)
+                                        ..snapshot.anchor_before(edit_end);
+                                    edit_start = edit_end;
+                                    Some((edit_range, String::new()))
+                                }
+                                CharOperation::Keep { bytes } => {
+                                    let edit_end = edit_start + bytes;
+                                    let edit_range = snapshot.anchor_after(edit_start)
+                                        ..snapshot.anchor_before(edit_end);
+                                    edit_start = edit_end;
+                                    codegen.last_equal_ranges.push(edit_range);
+                                    None
+                                }
+                            })
+                            .collect::<Vec<_>>();
 
-                            cx.notify();
-                        })?;
-                    }
+                        if codegen.active {
+                            codegen.apply_edits(edits.iter().cloned(), cx);
+                            codegen.reapply_line_based_diff(line_ops.iter().cloned(), cx);
+                        }
+                        codegen.edits.extend(edits);
+                        codegen.line_operations = line_ops;
+                        codegen.edit_position = Some(snapshot.anchor_after(edit_start));
+
+                        cx.notify();
+                    })?;
+                }
 
-                    // Streaming stopped and we have the new text in the buffer, and a line-based diff applied for the whole new buffer.
-                    // That diff is not what a regular diff is and might look unexpected, ergo apply a regular diff.
-                    // It's fine to apply even if the rest of the line diffing fails, as no more hunks are coming through `diff_rx`.
-                    let batch_diff_task =
-                        codegen.update(&mut cx, |codegen, cx| codegen.reapply_batch_diff(cx))?;
-                    let (line_based_stream_diff, ()) =
-                        join!(line_based_stream_diff, batch_diff_task);
-                    line_based_stream_diff?;
+                // Streaming stopped and we have the new text in the buffer, and a line-based diff applied for the whole new buffer.
+                // That diff is not what a regular diff is and might look unexpected, ergo apply a regular diff.
+                // It's fine to apply even if the rest of the line diffing fails, as no more hunks are coming through `diff_rx`.
+                let batch_diff_task =
+                    codegen.update(cx, |codegen, cx| codegen.reapply_batch_diff(cx))?;
+                let (line_based_stream_diff, ()) = join!(line_based_stream_diff, batch_diff_task);
+                line_based_stream_diff?;
 
-                    anyhow::Ok(())
-                };
+                anyhow::Ok(())
+            };
 
-                let result = generate.await;
-                let elapsed_time = start_time.elapsed().as_secs_f64();
+            let result = generate.await;
+            let elapsed_time = start_time.elapsed().as_secs_f64();
 
-                codegen
-                    .update(&mut cx, |this, cx| {
-                        this.message_id = message_id;
-                        this.last_equal_ranges.clear();
-                        if let Err(error) = result {
-                            this.status = CodegenStatus::Error(error);
-                        } else {
-                            this.status = CodegenStatus::Done;
-                        }
-                        this.elapsed_time = Some(elapsed_time);
-                        this.completion = Some(completion.lock().clone());
-                        cx.emit(CodegenEvent::Finished);
-                        cx.notify();
-                    })
-                    .ok();
-            }
+            codegen
+                .update(cx, |this, cx| {
+                    this.message_id = message_id;
+                    this.last_equal_ranges.clear();
+                    if let Err(error) = result {
+                        this.status = CodegenStatus::Error(error);
+                    } else {
+                        this.status = CodegenStatus::Done;
+                    }
+                    this.elapsed_time = Some(elapsed_time);
+                    this.completion = Some(completion.lock().clone());
+                    cx.emit(CodegenEvent::Finished);
+                    cx.notify();
+                })
+                .ok();
         });
         cx.notify();
     }
@@ -3323,7 +3317,7 @@ impl CodegenAlternative {
         let new_snapshot = self.buffer.read(cx).snapshot(cx);
         let new_range = self.range.to_point(&new_snapshot);
 
-        cx.spawn(|codegen, mut cx| async move {
+        cx.spawn(async move |codegen, cx| {
             let (deleted_row_ranges, inserted_row_ranges) = cx
                 .background_spawn(async move {
                     let old_text = old_snapshot
@@ -3373,7 +3367,7 @@ impl CodegenAlternative {
                 .await;
 
             codegen
-                .update(&mut cx, |codegen, cx| {
+                .update(cx, |codegen, cx| {
                     codegen.diff.deleted_row_ranges = deleted_row_ranges;
                     codegen.diff.inserted_row_ranges = inserted_row_ranges;
                     cx.notify();
@@ -3587,10 +3581,10 @@ impl CodeActionProvider for AssistantCodeActionProvider {
     ) -> Task<Result<ProjectTransaction>> {
         let editor = self.editor.clone();
         let workspace = self.workspace.clone();
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let editor = editor.upgrade().context("editor was released")?;
             let range = editor
-                .update(&mut cx, |editor, cx| {
+                .update(cx, |editor, cx| {
                     editor.buffer().update(cx, |multibuffer, cx| {
                         let buffer = buffer.read(cx);
                         let multibuffer_snapshot = multibuffer.read(cx);
@@ -3625,7 +3619,7 @@ impl CodeActionProvider for AssistantCodeActionProvider {
                     })
                 })?
                 .context("invalid range")?;
-            let assistant_panel = workspace.update(&mut cx, |workspace, cx| {
+            let assistant_panel = workspace.update(cx, |workspace, cx| {
                 workspace
                     .panel::<AssistantPanel>(cx)
                     .context("assistant panel was released")

crates/assistant/src/terminal_inline_assistant.rs 🔗

@@ -825,7 +825,7 @@ impl PromptEditor {
         let Some(model) = LanguageModelRegistry::read_global(cx).active_model() else {
             return;
         };
-        self.pending_token_count = cx.spawn(|this, mut cx| async move {
+        self.pending_token_count = cx.spawn(async move |this, cx| {
             cx.background_executor().timer(Duration::from_secs(1)).await;
             let request =
                 cx.update_global(|inline_assistant: &mut TerminalInlineAssistant, cx| {
@@ -833,7 +833,7 @@ impl PromptEditor {
                 })??;
 
             let token_count = cx.update(|cx| model.count_tokens(request, cx))?.await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.token_count = Some(token_count);
                 cx.notify();
             })
@@ -1140,7 +1140,7 @@ impl Codegen {
         let telemetry = self.telemetry.clone();
         self.status = CodegenStatus::Pending;
         self.transaction = Some(TerminalTransaction::start(self.terminal.clone()));
-        self.generation = cx.spawn(|this, mut cx| async move {
+        self.generation = cx.spawn(async move |this, cx| {
             let model_telemetry_id = model.telemetry_id();
             let model_provider_id = model.provider_id();
             let response = model.stream_completion_text(prompt, &cx).await;
@@ -1197,12 +1197,12 @@ impl Codegen {
                     }
                 });
 
-                this.update(&mut cx, |this, _| {
+                this.update(cx, |this, _| {
                     this.message_id = message_id;
                 })?;
 
                 while let Some(hunk) = hunks_rx.next().await {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         if let Some(transaction) = &mut this.transaction {
                             transaction.push(hunk, cx);
                             cx.notify();
@@ -1216,7 +1216,7 @@ impl Codegen {
 
             let result = generate.await;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 if let Err(error) = result {
                     this.status = CodegenStatus::Error(error);
                 } else {

crates/assistant2/src/active_thread.rs 🔗

@@ -372,10 +372,10 @@ impl ActiveThread {
                             cx,
                         );
 
-                        cx.spawn(|this, mut cx| async move {
+                        cx.spawn(async move |this, cx| {
                             let updated_context_ids = refresh_task.await;
 
-                            this.update(&mut cx, |this, cx| {
+                            this.update(cx, |this, cx| {
                                 this.context_store.read_with(cx, |context_store, cx| {
                                     context_store
                                         .context()
@@ -394,10 +394,10 @@ impl ActiveThread {
 
                     let model_registry = LanguageModelRegistry::read_global(cx);
                     if let Some(model) = model_registry.active_model() {
-                        cx.spawn(|this, mut cx| async move {
+                        cx.spawn(async move |this, cx| {
                             let updated_context = context_update_task.await?;
 
-                            this.update(&mut cx, |this, cx| {
+                            this.update(cx, |this, cx| {
                                 this.thread.update(cx, |thread, cx| {
                                     thread.attach_tool_results(updated_context, cx);
                                     if !canceled {
@@ -418,9 +418,9 @@ impl ActiveThread {
     /// Only one task to save the thread will be in flight at a time.
     fn save_thread(&mut self, cx: &mut Context<Self>) {
         let thread = self.thread.clone();
-        self.save_thread_task = Some(cx.spawn(|this, mut cx| async move {
+        self.save_thread_task = Some(cx.spawn(async move |this, cx| {
             let task = this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     this.thread_store
                         .update(cx, |thread_store, cx| thread_store.save_thread(&thread, cx))
                 })

crates/assistant2/src/assistant_panel.rs 🔗

@@ -110,16 +110,16 @@ impl AssistantPanel {
         prompt_builder: Arc<PromptBuilder>,
         cx: AsyncWindowContext,
     ) -> Task<Result<Entity<Self>>> {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let tools = Arc::new(ToolWorkingSet::default());
-            let thread_store = workspace.update(&mut cx, |workspace, cx| {
+            let thread_store = workspace.update(cx, |workspace, cx| {
                 let project = workspace.project().clone();
                 ThreadStore::new(project, tools.clone(), prompt_builder.clone(), cx)
             })??;
 
             let slash_commands = Arc::new(SlashCommandWorkingSet::default());
             let context_store = workspace
-                .update(&mut cx, |workspace, cx| {
+                .update(cx, |workspace, cx| {
                     let project = workspace.project().clone();
                     assistant_context_editor::ContextStore::new(
                         project,
@@ -130,7 +130,7 @@ impl AssistantPanel {
                 })?
                 .await?;
 
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 cx.new(|cx| Self::new(workspace, thread_store, context_store, window, cx))
             })
         })
@@ -344,9 +344,9 @@ impl AssistantPanel {
 
         let lsp_adapter_delegate = make_lsp_adapter_delegate(&project, cx).log_err().flatten();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let context = context.await?;
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 let editor = cx.new(|cx| {
                     ContextEditor::for_context(
                         context,
@@ -377,9 +377,9 @@ impl AssistantPanel {
             .thread_store
             .update(cx, |this, cx| this.open_thread(thread_id, cx));
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let thread = open_thread_task.await?;
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.active_view = ActiveView::Thread;
                 let message_editor_context_store =
                     cx.new(|_cx| crate::context_store::ContextStore::new(this.workspace.clone()));
@@ -450,10 +450,10 @@ impl AssistantPanel {
             .languages
             .language_for_name("Markdown");
         let thread = self.active_thread(cx);
-        cx.spawn_in(window, |_this, mut cx| async move {
+        cx.spawn_in(window, async move |_this, cx| {
             let markdown_language = markdown_language_task.await?;
 
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 let thread = thread.read(cx);
                 let markdown = thread.to_markdown()?;
                 let thread_summary = thread

crates/assistant2/src/buffer_codegen.rs 🔗

@@ -367,7 +367,7 @@ impl CodegenAlternative {
                 let request = self.build_request(user_prompt, cx)?;
                 self.request = Some(request.clone());
 
-                cx.spawn(|_, cx| async move { model.stream_completion_text(request, &cx).await })
+                cx.spawn(async move |_, cx| model.stream_completion_text(request, &cx).await)
                     .boxed_local()
             };
         self.handle_stream(telemetry_id, provider_id.to_string(), api_key, stream, cx);
@@ -480,213 +480,207 @@ impl CodegenAlternative {
         let completion = Arc::new(Mutex::new(String::new()));
         let completion_clone = completion.clone();
 
-        self.generation = cx.spawn(|codegen, mut cx| {
-            async move {
-                let stream = stream.await;
-                let message_id = stream
-                    .as_ref()
-                    .ok()
-                    .and_then(|stream| stream.message_id.clone());
-                let generate = async {
-                    let (mut diff_tx, mut diff_rx) = mpsc::channel(1);
-                    let executor = cx.background_executor().clone();
-                    let message_id = message_id.clone();
-                    let line_based_stream_diff: Task<anyhow::Result<()>> =
-                        cx.background_spawn(async move {
-                            let mut response_latency = None;
-                            let request_start = Instant::now();
-                            let diff = async {
-                                let chunks = StripInvalidSpans::new(stream?.stream);
-                                futures::pin_mut!(chunks);
-                                let mut diff = StreamingDiff::new(selected_text.to_string());
-                                let mut line_diff = LineDiff::default();
-
-                                let mut new_text = String::new();
-                                let mut base_indent = None;
-                                let mut line_indent = None;
-                                let mut first_line = true;
-
-                                while let Some(chunk) = chunks.next().await {
-                                    if response_latency.is_none() {
-                                        response_latency = Some(request_start.elapsed());
-                                    }
-                                    let chunk = chunk?;
-                                    completion_clone.lock().push_str(&chunk);
-
-                                    let mut lines = chunk.split('\n').peekable();
-                                    while let Some(line) = lines.next() {
-                                        new_text.push_str(line);
-                                        if line_indent.is_none() {
-                                            if let Some(non_whitespace_ch_ix) =
-                                                new_text.find(|ch: char| !ch.is_whitespace())
-                                            {
-                                                line_indent = Some(non_whitespace_ch_ix);
-                                                base_indent = base_indent.or(line_indent);
-
-                                                let line_indent = line_indent.unwrap();
-                                                let base_indent = base_indent.unwrap();
-                                                let indent_delta =
-                                                    line_indent as i32 - base_indent as i32;
-                                                let mut corrected_indent_len = cmp::max(
-                                                    0,
-                                                    suggested_line_indent.len as i32 + indent_delta,
-                                                )
-                                                    as usize;
-                                                if first_line {
-                                                    corrected_indent_len = corrected_indent_len
-                                                        .saturating_sub(
-                                                            selection_start.column as usize,
-                                                        );
-                                                }
-
-                                                let indent_char = suggested_line_indent.char();
-                                                let mut indent_buffer = [0; 4];
-                                                let indent_str =
-                                                    indent_char.encode_utf8(&mut indent_buffer);
-                                                new_text.replace_range(
-                                                    ..line_indent,
-                                                    &indent_str.repeat(corrected_indent_len),
-                                                );
+        self.generation = cx.spawn(async move |codegen, cx| {
+            let stream = stream.await;
+            let message_id = stream
+                .as_ref()
+                .ok()
+                .and_then(|stream| stream.message_id.clone());
+            let generate = async {
+                let (mut diff_tx, mut diff_rx) = mpsc::channel(1);
+                let executor = cx.background_executor().clone();
+                let message_id = message_id.clone();
+                let line_based_stream_diff: Task<anyhow::Result<()>> =
+                    cx.background_spawn(async move {
+                        let mut response_latency = None;
+                        let request_start = Instant::now();
+                        let diff = async {
+                            let chunks = StripInvalidSpans::new(stream?.stream);
+                            futures::pin_mut!(chunks);
+                            let mut diff = StreamingDiff::new(selected_text.to_string());
+                            let mut line_diff = LineDiff::default();
+
+                            let mut new_text = String::new();
+                            let mut base_indent = None;
+                            let mut line_indent = None;
+                            let mut first_line = true;
+
+                            while let Some(chunk) = chunks.next().await {
+                                if response_latency.is_none() {
+                                    response_latency = Some(request_start.elapsed());
+                                }
+                                let chunk = chunk?;
+                                completion_clone.lock().push_str(&chunk);
+
+                                let mut lines = chunk.split('\n').peekable();
+                                while let Some(line) = lines.next() {
+                                    new_text.push_str(line);
+                                    if line_indent.is_none() {
+                                        if let Some(non_whitespace_ch_ix) =
+                                            new_text.find(|ch: char| !ch.is_whitespace())
+                                        {
+                                            line_indent = Some(non_whitespace_ch_ix);
+                                            base_indent = base_indent.or(line_indent);
+
+                                            let line_indent = line_indent.unwrap();
+                                            let base_indent = base_indent.unwrap();
+                                            let indent_delta =
+                                                line_indent as i32 - base_indent as i32;
+                                            let mut corrected_indent_len = cmp::max(
+                                                0,
+                                                suggested_line_indent.len as i32 + indent_delta,
+                                            )
+                                                as usize;
+                                            if first_line {
+                                                corrected_indent_len = corrected_indent_len
+                                                    .saturating_sub(
+                                                        selection_start.column as usize,
+                                                    );
                                             }
-                                        }
 
-                                        if line_indent.is_some() {
-                                            let char_ops = diff.push_new(&new_text);
-                                            line_diff
-                                                .push_char_operations(&char_ops, &selected_text);
-                                            diff_tx
-                                                .send((char_ops, line_diff.line_operations()))
-                                                .await?;
-                                            new_text.clear();
-                                        }
-
-                                        if lines.peek().is_some() {
-                                            let char_ops = diff.push_new("\n");
-                                            line_diff
-                                                .push_char_operations(&char_ops, &selected_text);
-                                            diff_tx
-                                                .send((char_ops, line_diff.line_operations()))
-                                                .await?;
-                                            if line_indent.is_none() {
-                                                // Don't write out the leading indentation in empty lines on the next line
-                                                // This is the case where the above if statement didn't clear the buffer
-                                                new_text.clear();
-                                            }
-                                            line_indent = None;
-                                            first_line = false;
+                                            let indent_char = suggested_line_indent.char();
+                                            let mut indent_buffer = [0; 4];
+                                            let indent_str =
+                                                indent_char.encode_utf8(&mut indent_buffer);
+                                            new_text.replace_range(
+                                                ..line_indent,
+                                                &indent_str.repeat(corrected_indent_len),
+                                            );
                                         }
                                     }
-                                }
 
-                                let mut char_ops = diff.push_new(&new_text);
-                                char_ops.extend(diff.finish());
-                                line_diff.push_char_operations(&char_ops, &selected_text);
-                                line_diff.finish(&selected_text);
-                                diff_tx
-                                    .send((char_ops, line_diff.line_operations()))
-                                    .await?;
-
-                                anyhow::Ok(())
-                            };
-
-                            let result = diff.await;
-
-                            let error_message =
-                                result.as_ref().err().map(|error| error.to_string());
-                            report_assistant_event(
-                                AssistantEvent {
-                                    conversation_id: None,
-                                    message_id,
-                                    kind: AssistantKind::Inline,
-                                    phase: AssistantPhase::Response,
-                                    model: model_telemetry_id,
-                                    model_provider: model_provider_id.to_string(),
-                                    response_latency,
-                                    error_message,
-                                    language_name: language_name.map(|name| name.to_proto()),
-                                },
-                                telemetry,
-                                http_client,
-                                model_api_key,
-                                &executor,
-                            );
-
-                            result?;
-                            Ok(())
-                        });
-
-                    while let Some((char_ops, line_ops)) = diff_rx.next().await {
-                        codegen.update(&mut cx, |codegen, cx| {
-                            codegen.last_equal_ranges.clear();
-
-                            let edits = char_ops
-                                .into_iter()
-                                .filter_map(|operation| match operation {
-                                    CharOperation::Insert { text } => {
-                                        let edit_start = snapshot.anchor_after(edit_start);
-                                        Some((edit_start..edit_start, text))
-                                    }
-                                    CharOperation::Delete { bytes } => {
-                                        let edit_end = edit_start + bytes;
-                                        let edit_range = snapshot.anchor_after(edit_start)
-                                            ..snapshot.anchor_before(edit_end);
-                                        edit_start = edit_end;
-                                        Some((edit_range, String::new()))
-                                    }
-                                    CharOperation::Keep { bytes } => {
-                                        let edit_end = edit_start + bytes;
-                                        let edit_range = snapshot.anchor_after(edit_start)
-                                            ..snapshot.anchor_before(edit_end);
-                                        edit_start = edit_end;
-                                        codegen.last_equal_ranges.push(edit_range);
-                                        None
+                                    if line_indent.is_some() {
+                                        let char_ops = diff.push_new(&new_text);
+                                        line_diff.push_char_operations(&char_ops, &selected_text);
+                                        diff_tx
+                                            .send((char_ops, line_diff.line_operations()))
+                                            .await?;
+                                        new_text.clear();
                                     }
-                                })
-                                .collect::<Vec<_>>();
 
-                            if codegen.active {
-                                codegen.apply_edits(edits.iter().cloned(), cx);
-                                codegen.reapply_line_based_diff(line_ops.iter().cloned(), cx);
+                                    if lines.peek().is_some() {
+                                        let char_ops = diff.push_new("\n");
+                                        line_diff.push_char_operations(&char_ops, &selected_text);
+                                        diff_tx
+                                            .send((char_ops, line_diff.line_operations()))
+                                            .await?;
+                                        if line_indent.is_none() {
+                                            // Don't write out the leading indentation in empty lines on the next line
+                                            // This is the case where the above if statement didn't clear the buffer
+                                            new_text.clear();
+                                        }
+                                        line_indent = None;
+                                        first_line = false;
+                                    }
+                                }
                             }
-                            codegen.edits.extend(edits);
-                            codegen.line_operations = line_ops;
-                            codegen.edit_position = Some(snapshot.anchor_after(edit_start));
 
-                            cx.notify();
-                        })?;
-                    }
+                            let mut char_ops = diff.push_new(&new_text);
+                            char_ops.extend(diff.finish());
+                            line_diff.push_char_operations(&char_ops, &selected_text);
+                            line_diff.finish(&selected_text);
+                            diff_tx
+                                .send((char_ops, line_diff.line_operations()))
+                                .await?;
+
+                            anyhow::Ok(())
+                        };
+
+                        let result = diff.await;
+
+                        let error_message = result.as_ref().err().map(|error| error.to_string());
+                        report_assistant_event(
+                            AssistantEvent {
+                                conversation_id: None,
+                                message_id,
+                                kind: AssistantKind::Inline,
+                                phase: AssistantPhase::Response,
+                                model: model_telemetry_id,
+                                model_provider: model_provider_id.to_string(),
+                                response_latency,
+                                error_message,
+                                language_name: language_name.map(|name| name.to_proto()),
+                            },
+                            telemetry,
+                            http_client,
+                            model_api_key,
+                            &executor,
+                        );
+
+                        result?;
+                        Ok(())
+                    });
+
+                while let Some((char_ops, line_ops)) = diff_rx.next().await {
+                    codegen.update(cx, |codegen, cx| {
+                        codegen.last_equal_ranges.clear();
+
+                        let edits = char_ops
+                            .into_iter()
+                            .filter_map(|operation| match operation {
+                                CharOperation::Insert { text } => {
+                                    let edit_start = snapshot.anchor_after(edit_start);
+                                    Some((edit_start..edit_start, text))
+                                }
+                                CharOperation::Delete { bytes } => {
+                                    let edit_end = edit_start + bytes;
+                                    let edit_range = snapshot.anchor_after(edit_start)
+                                        ..snapshot.anchor_before(edit_end);
+                                    edit_start = edit_end;
+                                    Some((edit_range, String::new()))
+                                }
+                                CharOperation::Keep { bytes } => {
+                                    let edit_end = edit_start + bytes;
+                                    let edit_range = snapshot.anchor_after(edit_start)
+                                        ..snapshot.anchor_before(edit_end);
+                                    edit_start = edit_end;
+                                    codegen.last_equal_ranges.push(edit_range);
+                                    None
+                                }
+                            })
+                            .collect::<Vec<_>>();
 
-                    // Streaming stopped and we have the new text in the buffer, and a line-based diff applied for the whole new buffer.
-                    // That diff is not what a regular diff is and might look unexpected, ergo apply a regular diff.
-                    // It's fine to apply even if the rest of the line diffing fails, as no more hunks are coming through `diff_rx`.
-                    let batch_diff_task =
-                        codegen.update(&mut cx, |codegen, cx| codegen.reapply_batch_diff(cx))?;
-                    let (line_based_stream_diff, ()) =
-                        join!(line_based_stream_diff, batch_diff_task);
-                    line_based_stream_diff?;
-
-                    anyhow::Ok(())
-                };
-
-                let result = generate.await;
-                let elapsed_time = start_time.elapsed().as_secs_f64();
-
-                codegen
-                    .update(&mut cx, |this, cx| {
-                        this.message_id = message_id;
-                        this.last_equal_ranges.clear();
-                        if let Err(error) = result {
-                            this.status = CodegenStatus::Error(error);
-                        } else {
-                            this.status = CodegenStatus::Done;
+                        if codegen.active {
+                            codegen.apply_edits(edits.iter().cloned(), cx);
+                            codegen.reapply_line_based_diff(line_ops.iter().cloned(), cx);
                         }
-                        this.elapsed_time = Some(elapsed_time);
-                        this.completion = Some(completion.lock().clone());
-                        cx.emit(CodegenEvent::Finished);
+                        codegen.edits.extend(edits);
+                        codegen.line_operations = line_ops;
+                        codegen.edit_position = Some(snapshot.anchor_after(edit_start));
+
                         cx.notify();
-                    })
-                    .ok();
-            }
+                    })?;
+                }
+
+                // Streaming stopped and we have the new text in the buffer, and a line-based diff applied for the whole new buffer.
+                // That diff is not what a regular diff is and might look unexpected, ergo apply a regular diff.
+                // It's fine to apply even if the rest of the line diffing fails, as no more hunks are coming through `diff_rx`.
+                let batch_diff_task =
+                    codegen.update(cx, |codegen, cx| codegen.reapply_batch_diff(cx))?;
+                let (line_based_stream_diff, ()) = join!(line_based_stream_diff, batch_diff_task);
+                line_based_stream_diff?;
+
+                anyhow::Ok(())
+            };
+
+            let result = generate.await;
+            let elapsed_time = start_time.elapsed().as_secs_f64();
+
+            codegen
+                .update(cx, |this, cx| {
+                    this.message_id = message_id;
+                    this.last_equal_ranges.clear();
+                    if let Err(error) = result {
+                        this.status = CodegenStatus::Error(error);
+                    } else {
+                        this.status = CodegenStatus::Done;
+                    }
+                    this.elapsed_time = Some(elapsed_time);
+                    this.completion = Some(completion.lock().clone());
+                    cx.emit(CodegenEvent::Finished);
+                    cx.notify();
+                })
+                .ok();
         });
         cx.notify();
     }
@@ -804,7 +798,7 @@ impl CodegenAlternative {
         let new_snapshot = self.buffer.read(cx).snapshot(cx);
         let new_range = self.range.to_point(&new_snapshot);
 
-        cx.spawn(|codegen, mut cx| async move {
+        cx.spawn(async move |codegen, cx| {
             let (deleted_row_ranges, inserted_row_ranges) = cx
                 .background_spawn(async move {
                     let old_text = old_snapshot
@@ -854,7 +848,7 @@ impl CodegenAlternative {
                 .await;
 
             codegen
-                .update(&mut cx, |codegen, cx| {
+                .update(cx, |codegen, cx| {
                     codegen.diff.deleted_row_ranges = deleted_row_ranges;
                     codegen.diff.inserted_row_ranges = inserted_row_ranges;
                     cx.notify();

crates/assistant2/src/context_picker.rs 🔗

@@ -281,10 +281,8 @@ impl ContextPicker {
             context_store.add_file_from_path(project_path.clone(), cx)
         });
 
-        cx.spawn_in(window, |_, mut cx| async move {
-            task.await.notify_async_err(&mut cx)
-        })
-        .detach();
+        cx.spawn_in(window, async move |_, cx| task.await.notify_async_err(cx))
+            .detach();
 
         cx.notify();
     }
@@ -307,13 +305,13 @@ impl ContextPicker {
         };
 
         let open_thread_task = thread_store.update(cx, |this, cx| this.open_thread(&thread.id, cx));
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let thread = open_thread_task.await?;
-            context_store.update(&mut cx, |context_store, cx| {
+            context_store.update(cx, |context_store, cx| {
                 context_store.add_thread(thread, cx);
             })?;
 
-            this.update(&mut cx, |_this, cx| cx.notify())
+            this.update(cx, |_this, cx| cx.notify())
         })
     }
 

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

@@ -206,12 +206,12 @@ impl PickerDelegate for FetchContextPickerDelegate {
         let http_client = workspace.read(cx).client().http_client().clone();
         let url = self.url.clone();
         let confirm_behavior = self.confirm_behavior;
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let text = cx
                 .background_spawn(Self::build_message(http_client, url.clone()))
                 .await?;
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.delegate
                     .context_store
                     .update(cx, |context_store, _cx| {

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

@@ -206,11 +206,11 @@ impl PickerDelegate for FileContextPickerDelegate {
 
         let search_task = self.search(query, Arc::<AtomicBool>::default(), &workspace, cx);
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             // TODO: This should be probably be run in the background.
             let paths = search_task.await;
 
-            this.update(&mut cx, |this, _cx| {
+            this.update(cx, |this, _cx| {
                 this.delegate.matches = paths;
             })
             .log_err();
@@ -345,10 +345,10 @@ impl PickerDelegate for FileContextPickerDelegate {
         };
 
         let confirm_behavior = self.confirm_behavior;
-        cx.spawn_in(window, |this, mut cx| async move {
-            match task.await.notify_async_err(&mut cx) {
+        cx.spawn_in(window, async move |this, cx| {
+            match task.await.notify_async_err(cx) {
                 None => anyhow::Ok(()),
-                Some(()) => this.update_in(&mut cx, |this, window, cx| match confirm_behavior {
+                Some(()) => this.update_in(cx, |this, window, cx| match confirm_behavior {
                     ConfirmBehavior::KeepOpen => {}
                     ConfirmBehavior::Close => this.delegate.dismissed(window, cx),
                 }),

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

@@ -149,9 +149,9 @@ impl PickerDelegate for ThreadContextPickerDelegate {
             }
         });
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let matches = search_task.await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.delegate.matches = matches;
                 this.delegate.selected_index = 0;
                 cx.notify();
@@ -171,9 +171,9 @@ impl PickerDelegate for ThreadContextPickerDelegate {
 
         let open_thread_task = thread_store.update(cx, |this, cx| this.open_thread(&entry.id, cx));
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let thread = open_thread_task.await?;
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.delegate
                     .context_store
                     .update(cx, |context_store, cx| context_store.add_thread(thread, cx))

crates/assistant2/src/context_store.rs 🔗

@@ -75,15 +75,15 @@ impl ContextStore {
             return Task::ready(Err(anyhow!("failed to read project")));
         };
 
-        cx.spawn(|this, mut cx| async move {
-            let open_buffer_task = project.update(&mut cx, |project, cx| {
+        cx.spawn(async move |this, cx| {
+            let open_buffer_task = project.update(cx, |project, cx| {
                 project.open_buffer(project_path.clone(), cx)
             })?;
 
             let buffer_entity = open_buffer_task.await?;
-            let buffer_id = this.update(&mut cx, |_, cx| buffer_entity.read(cx).remote_id())?;
+            let buffer_id = this.update(cx, |_, cx| buffer_entity.read(cx).remote_id())?;
 
-            let already_included = this.update(&mut cx, |this, _cx| {
+            let already_included = this.update(cx, |this, _cx| {
                 match this.will_include_buffer(buffer_id, &project_path.path) {
                     Some(FileInclusion::Direct(context_id)) => {
                         this.remove_context(context_id);
@@ -98,7 +98,7 @@ impl ContextStore {
                 return anyhow::Ok(());
             }
 
-            let (buffer_info, text_task) = this.update(&mut cx, |_, cx| {
+            let (buffer_info, text_task) = this.update(cx, |_, cx| {
                 let buffer = buffer_entity.read(cx);
                 collect_buffer_info_and_text(
                     project_path.path.clone(),
@@ -110,7 +110,7 @@ impl ContextStore {
 
             let text = text_task.await;
 
-            this.update(&mut cx, |this, _cx| {
+            this.update(cx, |this, _cx| {
                 this.insert_file(make_context_buffer(buffer_info, text));
             })?;
 
@@ -123,8 +123,8 @@ impl ContextStore {
         buffer_entity: Entity<Buffer>,
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
-        cx.spawn(|this, mut cx| async move {
-            let (buffer_info, text_task) = this.update(&mut cx, |_, cx| {
+        cx.spawn(async move |this, cx| {
+            let (buffer_info, text_task) = this.update(cx, |_, cx| {
                 let buffer = buffer_entity.read(cx);
                 let Some(file) = buffer.file() else {
                     return Err(anyhow!("Buffer has no path."));
@@ -139,7 +139,7 @@ impl ContextStore {
 
             let text = text_task.await;
 
-            this.update(&mut cx, |this, _cx| {
+            this.update(cx, |this, _cx| {
                 this.insert_file(make_context_buffer(buffer_info, text))
             })?;
 
@@ -179,18 +179,18 @@ impl ContextStore {
         }
 
         let worktree_id = project_path.worktree_id;
-        cx.spawn(|this, mut cx| async move {
-            let worktree = project.update(&mut cx, |project, cx| {
+        cx.spawn(async move |this, cx| {
+            let worktree = project.update(cx, |project, cx| {
                 project
                     .worktree_for_id(worktree_id, cx)
                     .ok_or_else(|| anyhow!("no worktree found for {worktree_id:?}"))
             })??;
 
-            let files = worktree.update(&mut cx, |worktree, _cx| {
+            let files = worktree.update(cx, |worktree, _cx| {
                 collect_files_in_path(worktree, &project_path.path)
             })?;
 
-            let open_buffers_task = project.update(&mut cx, |project, cx| {
+            let open_buffers_task = project.update(cx, |project, cx| {
                 let tasks = files.iter().map(|file_path| {
                     project.open_buffer(
                         ProjectPath {
@@ -207,7 +207,7 @@ impl ContextStore {
 
             let mut buffer_infos = Vec::new();
             let mut text_tasks = Vec::new();
-            this.update(&mut cx, |_, cx| {
+            this.update(cx, |_, cx| {
                 for (path, buffer_entity) in files.into_iter().zip(buffers) {
                     // Skip all binary files and other non-UTF8 files
                     if let Ok(buffer_entity) = buffer_entity {
@@ -236,7 +236,7 @@ impl ContextStore {
                 bail!("No text files found in {}", &project_path.path.display());
             }
 
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 this.insert_directory(&project_path.path, context_buffers);
             })?;
 
@@ -595,10 +595,10 @@ fn refresh_file_text(
     let id = file_context.id;
     let task = refresh_context_buffer(&file_context.context_buffer, cx);
     if let Some(task) = task {
-        Some(cx.spawn(|mut cx| async move {
+        Some(cx.spawn(async move |cx| {
             let context_buffer = task.await;
             context_store
-                .update(&mut cx, |context_store, _| {
+                .update(cx, |context_store, _| {
                     let new_file_context = FileContext { id, context_buffer };
                     context_store.replace_context(AssistantContext::File(new_file_context));
                 })
@@ -636,10 +636,10 @@ fn refresh_directory_text(
 
     let id = directory_context.snapshot.id;
     let path = directory_context.path.clone();
-    Some(cx.spawn(|mut cx| async move {
+    Some(cx.spawn(async move |cx| {
         let context_buffers = context_buffers.await;
         context_store
-            .update(&mut cx, |context_store, _| {
+            .update(cx, |context_store, _| {
                 let new_directory_context = DirectoryContext::new(id, &path, context_buffers);
                 context_store.replace_context(AssistantContext::Directory(new_directory_context));
             })
@@ -654,9 +654,9 @@ fn refresh_thread_text(
 ) -> Task<()> {
     let id = thread_context.id;
     let thread = thread_context.thread.clone();
-    cx.spawn(move |mut cx| async move {
+    cx.spawn(async move |cx| {
         context_store
-            .update(&mut cx, |context_store, cx| {
+            .update(cx, |context_store, cx| {
                 let text = thread.read(cx).text().into();
                 context_store.replace_context(AssistantContext::Thread(ThreadContext {
                     id,

crates/assistant2/src/context_strip.rs 🔗

@@ -335,12 +335,12 @@ impl ContextStrip {
             context_store.accept_suggested_context(&suggested, cx)
         });
 
-        cx.spawn_in(window, |this, mut cx| async move {
-            match task.await.notify_async_err(&mut cx) {
+        cx.spawn_in(window, async move |this, cx| {
+            match task.await.notify_async_err(cx) {
                 None => {}
                 Some(()) => {
                     if let Some(this) = this.upgrade() {
-                        this.update(&mut cx, |_, cx| cx.notify())?;
+                        this.update(cx, |_, cx| cx.notify())?;
                     }
                 }
             }

crates/assistant2/src/inline_assistant.rs 🔗

@@ -276,7 +276,7 @@ impl InlineAssistant {
         if is_authenticated() {
             handle_assist(window, cx);
         } else {
-            cx.spawn_in(window, |_workspace, mut cx| async move {
+            cx.spawn_in(window, async move |_workspace, cx| {
                 let Some(task) = cx.update(|_, cx| {
                     LanguageModelRegistry::read_global(cx)
                         .active_provider()
@@ -1456,9 +1456,9 @@ impl EditorInlineAssists {
             assist_ids: Vec::new(),
             scroll_lock: None,
             highlight_updates: highlight_updates_tx,
-            _update_highlights: cx.spawn(|cx| {
+            _update_highlights: cx.spawn({
                 let editor = editor.downgrade();
-                async move {
+                async move |cx| {
                     while let Ok(()) = highlight_updates_rx.changed().await {
                         let editor = editor.upgrade().context("editor was dropped")?;
                         cx.update_global(|assistant: &mut InlineAssistant, cx| {
@@ -1748,10 +1748,10 @@ impl CodeActionProvider for AssistantCodeActionProvider {
         let editor = self.editor.clone();
         let workspace = self.workspace.clone();
         let thread_store = self.thread_store.clone();
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let editor = editor.upgrade().context("editor was released")?;
             let range = editor
-                .update(&mut cx, |editor, cx| {
+                .update(cx, |editor, cx| {
                     editor.buffer().update(cx, |multibuffer, cx| {
                         let buffer = buffer.read(cx);
                         let multibuffer_snapshot = multibuffer.read(cx);

crates/assistant2/src/message_editor.rs 🔗

@@ -206,10 +206,10 @@ impl MessageEditor {
 
         let thread = self.thread.clone();
         let context_store = self.context_store.clone();
-        cx.spawn(move |_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             refresh_task.await;
             thread
-                .update(&mut cx, |thread, cx| {
+                .update(cx, |thread, cx| {
                     let context = context_store.read(cx).snapshot(cx).collect::<Vec<_>>();
                     thread.insert_user_message(user_message, context, cx);
                     thread.send_to_model(model, request_kind, cx);
@@ -297,9 +297,9 @@ impl MessageEditor {
             .thread
             .update(cx, |thread, cx| thread.report_feedback(is_positive, cx));
 
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             report.await?;
-            workspace.update(&mut cx, |workspace, cx| {
+            workspace.update(cx, |workspace, cx| {
                 let message = if is_positive {
                     "Positive feedback recorded. Thank you!"
                 } else {

crates/assistant2/src/terminal_codegen.rs 🔗

@@ -40,7 +40,7 @@ impl TerminalCodegen {
         let telemetry = self.telemetry.clone();
         self.status = CodegenStatus::Pending;
         self.transaction = Some(TerminalTransaction::start(self.terminal.clone()));
-        self.generation = cx.spawn(|this, mut cx| async move {
+        self.generation = cx.spawn(async move |this, cx| {
             let model_telemetry_id = model.telemetry_id();
             let model_provider_id = model.provider_id();
             let response = model.stream_completion_text(prompt, &cx).await;
@@ -97,12 +97,12 @@ impl TerminalCodegen {
                     }
                 });
 
-                this.update(&mut cx, |this, _| {
+                this.update(cx, |this, _| {
                     this.message_id = message_id;
                 })?;
 
                 while let Some(hunk) = hunks_rx.next().await {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         if let Some(transaction) = &mut this.transaction {
                             transaction.push(hunk, cx);
                             cx.notify();
@@ -116,7 +116,7 @@ impl TerminalCodegen {
 
             let result = generate.await;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 if let Err(error) = result {
                     this.status = CodegenStatus::Error(error);
                 } else {

crates/assistant2/src/thread.rs 🔗

@@ -394,9 +394,9 @@ impl Thread {
     /// Serializes this thread into a format for storage or telemetry.
     pub fn serialize(&self, cx: &mut Context<Self>) -> Task<Result<SerializedThread>> {
         let initial_project_snapshot = self.initial_project_snapshot.clone();
-        cx.spawn(|this, cx| async move {
+        cx.spawn(async move |this, cx| {
             let initial_project_snapshot = initial_project_snapshot.await;
-            this.read_with(&cx, |this, _| SerializedThread {
+            this.read_with(cx, |this, _| SerializedThread {
                 summary: this.summary_or_default(),
                 updated_at: this.updated_at(),
                 messages: this
@@ -602,7 +602,7 @@ impl Thread {
     ) {
         let pending_completion_id = post_inc(&mut self.completion_count);
 
-        let task = cx.spawn(|thread, mut cx| async move {
+        let task = cx.spawn(async move |thread, cx| {
             let stream = model.stream_completion(request, &cx);
             let stream_completion = async {
                 let mut events = stream.await?;
@@ -612,7 +612,7 @@ impl Thread {
                 while let Some(event) = events.next().await {
                     let event = event?;
 
-                    thread.update(&mut cx, |thread, cx| {
+                    thread.update(cx, |thread, cx| {
                         match event {
                             LanguageModelCompletionEvent::StartMessage { .. } => {
                                 thread.insert_message(Role::Assistant, String::new(), cx);
@@ -671,7 +671,7 @@ impl Thread {
                     smol::future::yield_now().await;
                 }
 
-                thread.update(&mut cx, |thread, cx| {
+                thread.update(cx, |thread, cx| {
                     thread
                         .pending_completions
                         .retain(|completion| completion.id != pending_completion_id);
@@ -687,7 +687,7 @@ impl Thread {
             let result = stream_completion.await;
 
             thread
-                .update(&mut cx, |thread, cx| {
+                .update(cx, |thread, cx| {
                     match result.as_ref() {
                         Ok(stop_reason) => match stop_reason {
                             StopReason::ToolUse => {
@@ -750,7 +750,7 @@ impl Thread {
             cache: false,
         });
 
-        self.pending_summary = cx.spawn(|this, mut cx| {
+        self.pending_summary = cx.spawn(async move |this, cx| {
             async move {
                 let stream = model.stream_completion_text(request, &cx);
                 let mut messages = stream.await?;
@@ -767,7 +767,7 @@ impl Thread {
                     }
                 }
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     if !new_summary.is_empty() {
                         this.summary = Some(new_summary.into());
                     }
@@ -778,6 +778,7 @@ impl Thread {
                 anyhow::Ok(())
             }
             .log_err()
+            .await
         });
     }
 
@@ -823,10 +824,10 @@ impl Thread {
                         });
 
                     let session = self.scripting_session.clone();
-                    cx.spawn(|_, cx| async move {
+                    cx.spawn(async move |_, cx| {
                         script_task.await;
 
-                        let message = session.read_with(&cx, |session, _cx| {
+                        let message = session.read_with(cx, |session, _cx| {
                             // Using a id to get the script output seems impractical.
                             // Why not just include it in the Task result?
                             // This is because we'll later report the script state as it runs,
@@ -851,12 +852,12 @@ impl Thread {
         output: Task<Result<String>>,
         cx: &mut Context<Self>,
     ) {
-        let insert_output_task = cx.spawn(|thread, mut cx| {
+        let insert_output_task = cx.spawn({
             let tool_use_id = tool_use_id.clone();
-            async move {
+            async move |thread, cx| {
                 let output = output.await;
                 thread
-                    .update(&mut cx, |thread, cx| {
+                    .update(cx, |thread, cx| {
                         let pending_tool_use = thread
                             .tool_use
                             .insert_tool_output(tool_use_id.clone(), output);
@@ -881,12 +882,12 @@ impl Thread {
         output: Task<Result<String>>,
         cx: &mut Context<Self>,
     ) {
-        let insert_output_task = cx.spawn(|thread, mut cx| {
+        let insert_output_task = cx.spawn({
             let tool_use_id = tool_use_id.clone();
-            async move {
+            async move |thread, cx| {
                 let output = output.await;
                 thread
-                    .update(&mut cx, |thread, cx| {
+                    .update(cx, |thread, cx| {
                         let pending_tool_use = thread
                             .scripting_tool_use
                             .insert_tool_output(tool_use_id.clone(), output);
@@ -985,7 +986,7 @@ impl Thread {
             .map(|worktree| Self::worktree_snapshot(worktree, cx))
             .collect();
 
-        cx.spawn(move |_, cx| async move {
+        cx.spawn(async move |_, cx| {
             let worktree_snapshots = futures::future::join_all(worktree_snapshots).await;
 
             let mut unsaved_buffers = Vec::new();
@@ -1012,7 +1013,7 @@ impl Thread {
     }
 
     fn worktree_snapshot(worktree: Entity<project::Worktree>, cx: &App) -> Task<WorktreeSnapshot> {
-        cx.spawn(move |cx| async move {
+        cx.spawn(async move |cx| {
             // Get worktree path and snapshot
             let worktree_info = cx.update(|app_cx| {
                 let worktree = worktree.read(app_cx);
@@ -1036,7 +1037,7 @@ impl Thread {
                     let current_branch = repo_entry.branch().map(|branch| branch.name.to_string());
 
                     // Get repository info
-                    let repo_result = worktree.read_with(&cx, |worktree, _cx| {
+                    let repo_result = worktree.read_with(cx, |worktree, _cx| {
                         if let project::Worktree::Local(local_worktree) = &worktree {
                             local_worktree.get_local_repo(repo_entry).map(|local_repo| {
                                 let repo = local_repo.repo();
@@ -1051,7 +1052,7 @@ impl Thread {
                         Ok(Some((remote_url, head_sha, repository))) => {
                             // Get diff asynchronously
                             let diff = repository
-                                .diff(git::repository::DiffType::HeadToWorktree, cx)
+                                .diff(git::repository::DiffType::HeadToWorktree, cx.clone())
                                 .await
                                 .ok();
 

crates/assistant2/src/thread_store.rs 🔗

@@ -106,14 +106,14 @@ impl ThreadStore {
     ) -> Task<Result<Entity<Thread>>> {
         let id = id.clone();
         let database_future = ThreadsDatabase::global_future(cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let database = database_future.await.map_err(|err| anyhow!(err))?;
             let thread = database
                 .try_find_thread(id.clone())
                 .await?
                 .ok_or_else(|| anyhow!("no thread found with ID: {id:?}"))?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 cx.new(|cx| {
                     Thread::deserialize(
                         id.clone(),
@@ -133,23 +133,23 @@ impl ThreadStore {
             thread.update(cx, |thread, cx| (thread.id().clone(), thread.serialize(cx)));
 
         let database_future = ThreadsDatabase::global_future(cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let serialized_thread = serialized_thread.await?;
             let database = database_future.await.map_err(|err| anyhow!(err))?;
             database.save_thread(metadata, serialized_thread).await?;
 
-            this.update(&mut cx, |this, cx| this.reload(cx))?.await
+            this.update(cx, |this, cx| this.reload(cx))?.await
         })
     }
 
     pub fn delete_thread(&mut self, id: &ThreadId, cx: &mut Context<Self>) -> Task<Result<()>> {
         let id = id.clone();
         let database_future = ThreadsDatabase::global_future(cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let database = database_future.await.map_err(|err| anyhow!(err))?;
             database.delete_thread(id.clone()).await?;
 
-            this.update(&mut cx, |this, _cx| {
+            this.update(cx, |this, _cx| {
                 this.threads.retain(|thread| thread.id != id)
             })
         })
@@ -157,14 +157,14 @@ impl ThreadStore {
 
     pub fn reload(&self, cx: &mut Context<Self>) -> Task<Result<()>> {
         let database_future = ThreadsDatabase::global_future(cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let threads = database_future
                 .await
                 .map_err(|err| anyhow!(err))?
                 .list_threads()
                 .await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.threads = threads;
                 cx.notify();
             })
@@ -193,7 +193,7 @@ impl ThreadStore {
                     cx.spawn({
                         let server = server.clone();
                         let server_id = server_id.clone();
-                        |this, mut cx| async move {
+                        async move |this, cx| {
                             let Some(protocol) = server.client() else {
                                 return;
                             };
@@ -218,7 +218,7 @@ impl ThreadStore {
                                         })
                                         .collect::<Vec<_>>();
 
-                                    this.update(&mut cx, |this, _cx| {
+                                    this.update(cx, |this, _cx| {
                                         this.context_server_tool_ids.insert(server_id, tool_ids);
                                     })
                                     .log_err();

crates/assistant_context_editor/src/context.rs 🔗

@@ -1144,9 +1144,9 @@ impl AssistantContext {
 
     fn set_language(&mut self, cx: &mut Context<Self>) {
         let markdown = self.language_registry.language_for_name("Markdown");
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let markdown = markdown.await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.buffer
                     .update(cx, |buffer, cx| buffer.set_language(Some(markdown), cx));
             })
@@ -1188,7 +1188,7 @@ impl AssistantContext {
             return;
         };
         let debounce = self.token_count.is_some();
-        self.pending_token_count = cx.spawn(|this, mut cx| {
+        self.pending_token_count = cx.spawn(async move |this, cx| {
             async move {
                 if debounce {
                     cx.background_executor()
@@ -1197,13 +1197,14 @@ impl AssistantContext {
                 }
 
                 let token_count = cx.update(|cx| model.count_tokens(request, cx))?.await?;
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.token_count = Some(token_count);
                     this.start_cache_warming(&model, cx);
                     cx.notify()
                 })
             }
             .log_err()
+            .await
         });
     }
 
@@ -1342,7 +1343,7 @@ impl AssistantContext {
         };
 
         let model = Arc::clone(model);
-        self.pending_cache_warming_task = cx.spawn(|this, mut cx| {
+        self.pending_cache_warming_task = cx.spawn(async move |this, cx| {
             async move {
                 match model.stream_completion(request, &cx).await {
                     Ok(mut stream) => {
@@ -1353,13 +1354,14 @@ impl AssistantContext {
                         log::warn!("Cache warming failed: {}", e);
                     }
                 };
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.update_cache_status_for_completion(cx);
                 })
                 .ok();
                 anyhow::Ok(())
             }
             .log_err()
+            .await
         });
     }
 
@@ -1916,7 +1918,7 @@ impl AssistantContext {
             });
         self.reparse(cx);
 
-        let insert_output_task = cx.spawn(|this, mut cx| async move {
+        let insert_output_task = cx.spawn(async move |this, cx| {
             let run_command = async {
                 let mut stream = output.await?;
 
@@ -1933,7 +1935,7 @@ impl AssistantContext {
 
                 while let Some(event) = stream.next().await {
                     let event = event?;
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.buffer.update(cx, |buffer, _cx| {
                             buffer.finalize_last_transaction();
                             buffer.start_transaction()
@@ -2034,7 +2036,7 @@ impl AssistantContext {
                     })?;
                 }
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.buffer.update(cx, |buffer, cx| {
                         buffer.finalize_last_transaction();
                         buffer.start_transaction();
@@ -2080,7 +2082,7 @@ impl AssistantContext {
 
             let command_result = run_command.await;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let version = this.version.clone();
                 let timestamp = this.next_timestamp();
                 let Some(invoked_slash_command) = this.invoked_slash_commands.get_mut(&command_id)
@@ -2210,7 +2212,7 @@ impl AssistantContext {
         let pending_completion_id = post_inc(&mut self.completion_count);
 
         let task = cx.spawn({
-            |this, mut cx| async move {
+            async move |this, cx| {
                 let stream = model.stream_completion(request, &cx);
                 let assistant_message_id = assistant_message.id;
                 let mut response_latency = None;
@@ -2225,7 +2227,7 @@ impl AssistantContext {
                         }
                         let event = event?;
 
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             let message_ix = this
                                 .message_anchors
                                 .iter()
@@ -2264,7 +2266,7 @@ impl AssistantContext {
                         })?;
                         smol::future::yield_now().await;
                     }
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.pending_completions
                             .retain(|completion| completion.id != pending_completion_id);
                         this.summarize(false, cx);
@@ -2276,7 +2278,7 @@ impl AssistantContext {
 
                 let result = stream_completion.await;
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     let error_message = if let Some(error) = result.as_ref().err() {
                         if error.is::<PaymentRequiredError>() {
                             cx.emit(ContextEvent::ShowPaymentRequiredError);
@@ -2786,7 +2788,7 @@ impl AssistantContext {
                 cache: false,
             });
 
-            self.pending_summary = cx.spawn(|this, mut cx| {
+            self.pending_summary = cx.spawn(async move |this, cx| {
                 async move {
                     let stream = model.stream_completion_text(request, &cx);
                     let mut messages = stream.await?;
@@ -2795,7 +2797,7 @@ impl AssistantContext {
                     while let Some(message) = messages.stream.next().await {
                         let text = message?;
                         let mut lines = text.lines();
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             let version = this.version.clone();
                             let timestamp = this.next_timestamp();
                             let summary = this.summary.get_or_insert(ContextSummary::default());
@@ -2819,7 +2821,7 @@ impl AssistantContext {
                         }
                     }
 
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         let version = this.version.clone();
                         let timestamp = this.next_timestamp();
                         if let Some(summary) = this.summary.as_mut() {
@@ -2837,6 +2839,7 @@ impl AssistantContext {
                     anyhow::Ok(())
                 }
                 .log_err()
+                .await
             });
         }
     }
@@ -2943,12 +2946,12 @@ impl AssistantContext {
             return;
         }
 
-        self.pending_save = cx.spawn(|this, mut cx| async move {
+        self.pending_save = cx.spawn(async move |this, cx| {
             if let Some(debounce) = debounce {
                 cx.background_executor().timer(debounce).await;
             }
 
-            let (old_path, summary) = this.read_with(&cx, |this, _| {
+            let (old_path, summary) = this.read_with(cx, |this, _| {
                 let path = this.path.clone();
                 let summary = if let Some(summary) = this.summary.as_ref() {
                     if summary.done {
@@ -2963,7 +2966,7 @@ impl AssistantContext {
             })?;
 
             if let Some(summary) = summary {
-                let context = this.read_with(&cx, |this, cx| this.serialize(cx))?;
+                let context = this.read_with(cx, |this, cx| this.serialize(cx))?;
                 let mut discriminant = 1;
                 let mut new_path;
                 loop {
@@ -2995,7 +2998,7 @@ impl AssistantContext {
                     }
                 }
 
-                this.update(&mut cx, |this, _| this.path = Some(new_path))?;
+                this.update(cx, |this, _| this.path = Some(new_path))?;
             }
 
             Ok(())

crates/assistant_context_editor/src/context_editor.rs 🔗

@@ -907,7 +907,7 @@ impl ContextEditor {
                         if editor_state.opened_patch != patch {
                             state.update_task = Some({
                                 let this = this.clone();
-                                cx.spawn_in(window, |_, cx| async move {
+                                cx.spawn_in(window, async move |_, cx| {
                                     Self::update_patch_editor(this.clone(), patch, cx)
                                         .await
                                         .log_err();
@@ -1070,10 +1070,9 @@ impl ContextEditor {
                         })
                         .ok();
                 } else {
-                    patch_state.update_task =
-                        Some(cx.spawn_in(window, move |this, cx| async move {
-                            Self::open_patch_editor(this, new_patch, cx).await.log_err();
-                        }));
+                    patch_state.update_task = Some(cx.spawn_in(window, async move |this, cx| {
+                        Self::open_patch_editor(this, new_patch, cx).await.log_err();
+                    }));
                 }
             }
         }
@@ -1103,10 +1102,10 @@ impl ContextEditor {
     async fn open_patch_editor(
         this: WeakEntity<Self>,
         patch: AssistantPatch,
-        mut cx: AsyncWindowContext,
+        cx: &mut AsyncWindowContext,
     ) -> Result<()> {
-        let project = this.read_with(&cx, |this, _| this.project.clone())?;
-        let resolved_patch = patch.resolve(project.clone(), &mut cx).await;
+        let project = this.read_with(cx, |this, _| this.project.clone())?;
+        let resolved_patch = patch.resolve(project.clone(), cx).await;
 
         let editor = cx.new_window_entity(|window, cx| {
             let editor = ProposedChangesEditor::new(
@@ -1130,7 +1129,7 @@ impl ContextEditor {
             editor
         })?;
 
-        this.update(&mut cx, |this, _| {
+        this.update(cx, |this, _| {
             if let Some(patch_state) = this.patches.get_mut(&patch.range) {
                 patch_state.editor = Some(PatchEditorState {
                     editor: editor.downgrade(),
@@ -1139,8 +1138,8 @@ impl ContextEditor {
                 patch_state.update_task.take();
             }
         })?;
-        this.read_with(&cx, |this, _| this.workspace.clone())?
-            .update_in(&mut cx, |workspace, window, cx| {
+        this.read_with(cx, |this, _| this.workspace.clone())?
+            .update_in(cx, |workspace, window, cx| {
                 workspace.add_item_to_active_pane(Box::new(editor.clone()), None, false, window, cx)
             })
             .log_err();
@@ -1151,11 +1150,11 @@ impl ContextEditor {
     async fn update_patch_editor(
         this: WeakEntity<Self>,
         patch: AssistantPatch,
-        mut cx: AsyncWindowContext,
+        cx: &mut AsyncWindowContext,
     ) -> Result<()> {
-        let project = this.update(&mut cx, |this, _| this.project.clone())?;
-        let resolved_patch = patch.resolve(project.clone(), &mut cx).await;
-        this.update_in(&mut cx, |this, window, cx| {
+        let project = this.update(cx, |this, _| this.project.clone())?;
+        let resolved_patch = patch.resolve(project.clone(), cx).await;
+        this.update_in(cx, |this, window, cx| {
             let patch_state = this.patches.get_mut(&patch.range)?;
 
             let locations = resolved_patch
@@ -1625,14 +1624,14 @@ impl ContextEditor {
                     .map(|path| Workspace::project_path_for_path(project.clone(), &path, false, cx))
                     .collect::<Vec<_>>();
 
-                cx.spawn(move |_, cx| async move {
+                cx.spawn(async move |_, cx| {
                     let mut paths = vec![];
                     let mut worktrees = vec![];
 
                     let opened_paths = futures::future::join_all(tasks).await;
                     for (worktree, project_path) in opened_paths.into_iter().flatten() {
                         let Ok(worktree_root_name) =
-                            worktree.read_with(&cx, |worktree, _| worktree.root_name().to_string())
+                            worktree.read_with(cx, |worktree, _| worktree.root_name().to_string())
                         else {
                             continue;
                         };
@@ -1649,12 +1648,12 @@ impl ContextEditor {
         };
 
         window
-            .spawn(cx, |mut cx| async move {
+            .spawn(cx, async move |cx| {
                 let (paths, dragged_file_worktrees) = paths.await;
                 let cmd_name = FileSlashCommand.name();
 
                 context_editor_view
-                    .update_in(&mut cx, |context_editor, window, cx| {
+                    .update_in(cx, |context_editor, window, cx| {
                         let file_argument = paths
                             .into_iter()
                             .map(|path| path.to_string_lossy().to_string())
@@ -2200,9 +2199,9 @@ impl ContextEditor {
                                     .log_err();
 
                                 if let Some(client) = client {
-                                    cx.spawn(|this, mut cx| async move {
-                                        client.authenticate_and_connect(true, &mut cx).await?;
-                                        this.update(&mut cx, |_, cx| cx.notify())
+                                    cx.spawn(async move |this, cx| {
+                                        client.authenticate_and_connect(true, cx).await?;
+                                        this.update(cx, |_, cx| cx.notify())
                                     })
                                     .detach_and_log_err(cx)
                                 }
@@ -3161,10 +3160,10 @@ impl FollowableItem for ContextEditor {
             assistant_panel_delegate.open_remote_context(workspace, context_id, window, cx)
         });
 
-        Some(window.spawn(cx, |mut cx| async move {
+        Some(window.spawn(cx, async move |cx| {
             let context_editor = context_editor_task.await?;
             context_editor
-                .update_in(&mut cx, |context_editor, window, cx| {
+                .update_in(cx, |context_editor, window, cx| {
                     context_editor.remote_id = Some(id);
                     context_editor.editor.update(cx, |editor, cx| {
                         editor.apply_update_proto(

crates/assistant_context_editor/src/context_history.rs 🔗

@@ -164,9 +164,9 @@ impl PickerDelegate for SavedContextPickerDelegate {
         cx: &mut Context<Picker<Self>>,
     ) -> Task<()> {
         let search = self.store.read(cx).search(query, cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let matches = search.await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let host_contexts = this.delegate.store.read(cx).host_contexts();
                 this.delegate.matches = host_contexts
                     .iter()

crates/assistant_context_editor/src/context_store.rs 🔗

@@ -100,7 +100,7 @@ impl ContextStore {
         let fs = project.read(cx).fs().clone();
         let languages = project.read(cx).languages().clone();
         let telemetry = project.read(cx).client().telemetry().clone();
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             const CONTEXT_WATCH_DURATION: Duration = Duration::from_millis(100);
             let (mut events, _) = fs.watch(contexts_dir(), CONTEXT_WATCH_DURATION).await;
 
@@ -125,16 +125,15 @@ impl ContextStore {
                         languages,
                         slash_commands,
                         telemetry,
-                        _watch_updates: cx.spawn(|this, mut cx| {
+                        _watch_updates: cx.spawn(async move |this, cx| {
                             async move {
                                 while events.next().await.is_some() {
-                                    this.update(&mut cx, |this, cx| this.reload(cx))?
-                                        .await
-                                        .log_err();
+                                    this.update(cx, |this, cx| this.reload(cx))?.await.log_err();
                                 }
                                 anyhow::Ok(())
                             }
                             .log_err()
+                            .await
                         }),
                         client_subscription: None,
                         _project_subscriptions: vec![
@@ -395,7 +394,7 @@ impl ContextStore {
         let prompt_builder = self.prompt_builder.clone();
         let slash_commands = self.slash_commands.clone();
         let request = self.client.request(proto::CreateContext { project_id });
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = request.await?;
             let context_id = ContextId::from_proto(response.context_id);
             let context_proto = response.context.context("invalid context")?;
@@ -421,8 +420,8 @@ impl ContextStore {
                         .collect::<Result<Vec<_>>>()
                 })
                 .await?;
-            context.update(&mut cx, |context, cx| context.apply_ops(operations, cx))?;
-            this.update(&mut cx, |this, cx| {
+            context.update(cx, |context, cx| context.apply_ops(operations, cx))?;
+            this.update(cx, |this, cx| {
                 if let Some(existing_context) = this.loaded_context_for_id(&context_id, cx) {
                     existing_context
                 } else {
@@ -457,7 +456,7 @@ impl ContextStore {
         let prompt_builder = self.prompt_builder.clone();
         let slash_commands = self.slash_commands.clone();
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let saved_context = load.await?;
             let context = cx.new(|cx| {
                 AssistantContext::deserialize(
@@ -471,7 +470,7 @@ impl ContextStore {
                     cx,
                 )
             })?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 if let Some(existing_context) = this.loaded_context_for_path(&path, cx) {
                     existing_context
                 } else {
@@ -489,7 +488,7 @@ impl ContextStore {
     ) -> Task<Result<()>> {
         let fs = self.fs.clone();
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             fs.remove_file(
                 &path,
                 RemoveOptions {
@@ -499,7 +498,7 @@ impl ContextStore {
             )
             .await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.contexts.retain(|context| {
                     context
                         .upgrade()
@@ -565,7 +564,7 @@ impl ContextStore {
         });
         let prompt_builder = self.prompt_builder.clone();
         let slash_commands = self.slash_commands.clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = request.await?;
             let context_proto = response.context.context("invalid context")?;
             let context = cx.new(|cx| {
@@ -590,8 +589,8 @@ impl ContextStore {
                         .collect::<Result<Vec<_>>>()
                 })
                 .await?;
-            context.update(&mut cx, |context, cx| context.apply_ops(operations, cx))?;
-            this.update(&mut cx, |this, cx| {
+            context.update(cx, |context, cx| context.apply_ops(operations, cx))?;
+            this.update(cx, |this, cx| {
                 if let Some(existing_context) = this.loaded_context_for_id(&context_id, cx) {
                     existing_context
                 } else {
@@ -700,12 +699,12 @@ impl ContextStore {
             project_id,
             contexts,
         });
-        cx.spawn(|this, cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = request.await?;
 
             let mut context_ids = Vec::new();
             let mut operations = Vec::new();
-            this.read_with(&cx, |this, cx| {
+            this.read_with(cx, |this, cx| {
                 for context_version_proto in response.contexts {
                     let context_version = ContextVersion::from_proto(&context_version_proto);
                     let context_id = ContextId::from_proto(context_version_proto.context_id);
@@ -768,7 +767,7 @@ impl ContextStore {
 
     fn reload(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
         let fs = self.fs.clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             fs.create_dir(contexts_dir()).await?;
 
             let mut paths = fs.read_dir(contexts_dir()).await?;
@@ -808,7 +807,7 @@ impl ContextStore {
             }
             contexts.sort_unstable_by_key(|context| Reverse(context.mtime));
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.contexts_metadata = contexts;
                 cx.notify();
             })
@@ -850,7 +849,7 @@ impl ContextStore {
                     cx.spawn({
                         let server = server.clone();
                         let server_id = server_id.clone();
-                        |this, mut cx| async move {
+                        async move |this, cx| {
                             let Some(protocol) = server.client() else {
                                 return;
                             };
@@ -875,7 +874,7 @@ impl ContextStore {
                                         })
                                         .collect::<Vec<_>>();
 
-                                    this.update(&mut cx, |this, _cx| {
+                                    this.update( cx, |this, _cx| {
                                         this.context_server_slash_command_ids
                                             .insert(server_id.clone(), slash_command_ids);
                                     })

crates/assistant_context_editor/src/slash_command.rs 🔗

@@ -59,7 +59,7 @@ impl SlashCommandCompletionProvider {
         let command_name = command_name.to_string();
         let editor = self.editor.clone();
         let workspace = self.workspace.clone();
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let matches = match_strings(
                 &candidates,
                 &command_name,

crates/assistant_context_editor/src/slash_command_picker.rs 🔗

@@ -100,7 +100,7 @@ impl PickerDelegate for SlashCommandDelegate {
         cx: &mut Context<Picker<Self>>,
     ) -> Task<()> {
         let all_commands = self.all_commands.clone();
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let filtered_commands = cx
                 .background_spawn(async move {
                     if query.is_empty() {
@@ -119,7 +119,7 @@ impl PickerDelegate for SlashCommandDelegate {
                 })
                 .await;
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.delegate.filtered_commands = filtered_commands;
                 this.delegate.set_selected_index(0, window, cx);
                 cx.notify();

crates/assistant_eval/src/eval.rs 🔗

@@ -63,14 +63,14 @@ impl Eval {
         model: Arc<dyn LanguageModel>,
         cx: &mut App,
     ) -> Task<anyhow::Result<EvalOutput>> {
-        cx.spawn(move |mut cx| async move {
+        cx.spawn(async move |cx| {
             checkout_repo(&self.eval_setup, &self.repo_path).await?;
 
             let (assistant, done_rx) =
                 cx.update(|cx| HeadlessAssistant::new(app_state.clone(), cx))??;
 
             let _worktree = assistant
-                .update(&mut cx, |assistant, cx| {
+                .update(cx, |assistant, cx| {
                     assistant.project.update(cx, |project, cx| {
                         project.create_worktree(&self.repo_path, true, cx)
                     })
@@ -79,7 +79,7 @@ impl Eval {
 
             let start_time = std::time::SystemTime::now();
 
-            assistant.update(&mut cx, |assistant, cx| {
+            assistant.update(cx, |assistant, cx| {
                 assistant.thread.update(cx, |thread, cx| {
                     let context = vec![];
                     thread.insert_user_message(self.user_prompt.clone(), context, cx);
@@ -93,7 +93,7 @@ impl Eval {
 
             let diff = query_git(&self.repo_path, vec!["diff"]).await?;
 
-            assistant.update(&mut cx, |assistant, cx| {
+            assistant.update(cx, |assistant, cx| {
                 let thread = assistant.thread.read(cx);
                 let last_message = thread.messages().last().unwrap();
                 if last_message.role != language_model::Role::Assistant {

crates/assistant_eval/src/headless_assistant.rs 🔗

@@ -212,7 +212,7 @@ pub fn authenticate_model_provider(
 pub async fn send_language_model_request(
     model: Arc<dyn LanguageModel>,
     request: LanguageModelRequest,
-    cx: AsyncApp,
+    cx: &mut AsyncApp,
 ) -> anyhow::Result<String> {
     match model.stream_completion_text(request, &cx).await {
         Ok(mut stream) => {

crates/assistant_eval/src/judge.rs 🔗

@@ -61,7 +61,7 @@ impl Judge {
         };
 
         let model = self.model.clone();
-        cx.spawn(move |cx| send_language_model_request(model, request, cx))
+        cx.spawn(async move |cx| send_language_model_request(model, request, cx).await)
     }
 }
 

crates/assistant_eval/src/main.rs 🔗

@@ -111,7 +111,7 @@ fn main() {
         let editor_model_provider_id = editor_model.provider_id();
         let judge_model_provider_id = judge_model.provider_id();
 
-        cx.spawn(move |cx| async move {
+        cx.spawn(async move |cx| {
             // Authenticate all model providers first
             cx.update(|cx| authenticate_model_provider(model_provider_id.clone(), cx))
                 .unwrap()

crates/assistant_slash_commands/src/auto_command.rs 🔗

@@ -77,8 +77,8 @@ impl SlashCommand for AutoCommand {
 
         let cx: &mut App = cx;
 
-        cx.spawn(|cx: gpui::AsyncApp| async move {
-            let task = project_index.read_with(&cx, |project_index, cx| {
+        cx.spawn(async move |cx| {
+            let task = project_index.read_with(cx, |project_index, cx| {
                 project_index.flush_summary_backlogs(cx)
             })?;
 
@@ -117,9 +117,9 @@ impl SlashCommand for AutoCommand {
             return Task::ready(Err(anyhow!("no project indexer")));
         };
 
-        let task = window.spawn(cx, |cx| async move {
+        let task = window.spawn(cx, async move |cx| {
             let summaries = project_index
-                .read_with(&cx, |project_index, cx| project_index.all_summaries(cx))?
+                .read_with(cx, |project_index, cx| project_index.all_summaries(cx))?
                 .await?;
 
             commands_for_summaries(&summaries, &original_prompt, &cx).await

crates/assistant_slash_commands/src/diagnostics_command.rs 🔗

@@ -186,7 +186,7 @@ impl SlashCommand for DiagnosticsSlashCommand {
 
         let task = collect_diagnostics(workspace.read(cx).project().clone(), options, cx);
 
-        window.spawn(cx, move |_| async move {
+        window.spawn(cx, async move |_| {
             task.await?
                 .map(|output| output.to_event_stream())
                 .ok_or_else(|| anyhow!("No diagnostics found"))
@@ -268,7 +268,7 @@ fn collect_diagnostics(
         })
         .collect();
 
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         let mut output = SlashCommandOutput::default();
 
         if let Some(error_source) = error_source.as_ref() {
@@ -299,7 +299,7 @@ fn collect_diagnostics(
             }
 
             if let Some(buffer) = project_handle
-                .update(&mut cx, |project, cx| project.open_buffer(project_path, cx))?
+                .update(cx, |project, cx| project.open_buffer(project_path, cx))?
                 .await
                 .log_err()
             {

crates/assistant_slash_commands/src/file_command.rs 🔗

@@ -241,7 +241,7 @@ fn collect_files(
         .collect::<Vec<_>>();
 
     let (events_tx, events_rx) = mpsc::unbounded();
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         for snapshot in snapshots {
             let worktree_id = snapshot.id();
             let mut directory_stack: Vec<Arc<Path>> = Vec::new();
@@ -352,7 +352,7 @@ fn collect_files(
                     )))?;
                 } else if entry.is_file() {
                     let Some(open_buffer_task) = project_handle
-                        .update(&mut cx, |project, cx| {
+                        .update(cx, |project, cx| {
                             project.open_buffer((worktree_id, &entry.path), cx)
                         })
                         .ok()
@@ -361,7 +361,7 @@ fn collect_files(
                     };
                     if let Some(buffer) = open_buffer_task.await.log_err() {
                         let mut output = SlashCommandOutput::default();
-                        let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot())?;
+                        let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
                         append_buffer_to_output(
                             &snapshot,
                             Some(&path_including_worktree_name),

crates/assistant_slash_commands/src/project_command.rs 🔗

@@ -99,7 +99,7 @@ impl SlashCommand for ProjectSlashCommand {
             return Task::ready(Err(anyhow::anyhow!("no project indexer")));
         };
 
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let current_model = current_model.ok_or_else(|| anyhow!("no model selected"))?;
 
             let prompt =
@@ -123,7 +123,7 @@ impl SlashCommand for ProjectSlashCommand {
                 .search_queries;
 
             let results = project_index
-                .read_with(&cx, |project_index, cx| {
+                .read_with(cx, |project_index, cx| {
                     project_index.search(search_queries.clone(), 25, cx)
                 })?
                 .await?;

crates/assistant_slash_commands/src/search_command.rs 🔗

@@ -109,9 +109,9 @@ impl SlashCommand for SearchSlashCommand {
             return Task::ready(Err(anyhow::anyhow!("no project indexer")));
         };
 
-        window.spawn(cx, |cx| async move {
+        window.spawn(cx, async move |cx| {
             let results = project_index
-                .read_with(&cx, |project_index, cx| {
+                .read_with(cx, |project_index, cx| {
                     project_index.search(vec![query.clone()], limit.unwrap_or(5), cx)
                 })?
                 .await?;

crates/assistant_slash_commands/src/tab_command.rs 🔗

@@ -86,7 +86,7 @@ impl SlashCommand for TabSlashCommand {
             tab_items_for_queries(workspace, &[current_query], cancel, false, window, cx);
 
         let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId);
-        window.spawn(cx, |_| async move {
+        window.spawn(cx, async move |_| {
             let tab_items = tab_items_search.await?;
             let run_command = tab_items.len() == 1;
             let tab_completion_items = tab_items.into_iter().filter_map(|(path, ..)| {
@@ -172,11 +172,11 @@ fn tab_items_for_queries(
 ) -> Task<anyhow::Result<Vec<(Option<PathBuf>, BufferSnapshot, usize)>>> {
     let empty_query = queries.is_empty() || queries.iter().all(|query| query.trim().is_empty());
     let queries = queries.to_owned();
-    window.spawn(cx, |mut cx| async move {
+    window.spawn(cx, async move |cx| {
         let mut open_buffers =
             workspace
                 .context("no workspace")?
-                .update(&mut cx, |workspace, cx| {
+                .update(cx, |workspace, cx| {
                     if strict_match && empty_query {
                         let snapshot = active_item_buffer(workspace, cx)?;
                         let full_path = snapshot.resolve_file_path(cx, true);

crates/assistant_tools/src/bash_tool.rs 🔗

@@ -50,7 +50,7 @@ impl Tool for BashTool {
         };
         let working_directory = worktree.read(cx).abs_path();
 
-        cx.spawn(|_| async move {
+        cx.spawn(async move |_| {
             // Add 2>&1 to merge stderr into stdout for proper interleaving.
             let command = format!("({}) 2>&1", input.command);
 

crates/assistant_tools/src/diagnostics_tool.rs 🔗

@@ -65,10 +65,10 @@ impl Tool for DiagnosticsTool {
             };
             let buffer = project.update(cx, |project, cx| project.open_buffer(project_path, cx));
 
-            cx.spawn(|cx| async move {
+            cx.spawn(async move |cx| {
                 let mut output = String::new();
                 let buffer = buffer.await?;
-                let snapshot = buffer.read_with(&cx, |buffer, _cx| buffer.snapshot())?;
+                let snapshot = buffer.read_with(cx, |buffer, _cx| buffer.snapshot())?;
 
                 for (_, group) in snapshot.diagnostic_groups(None) {
                     let entry = &group.entries[group.primary_ix];

crates/assistant_tools/src/edit_files_tool.rs 🔗

@@ -103,7 +103,7 @@ impl Tool for EditFilesTool {
                     cx,
                 );
 
-                cx.spawn(|mut cx| async move {
+                cx.spawn(async move |cx| {
                     let result = task.await;
 
                     let str_result = match &result {
@@ -111,10 +111,8 @@ impl Tool for EditFilesTool {
                         Err(err) => Err(err.to_string()),
                     };
 
-                    log.update(&mut cx, |log, cx| {
-                        log.set_tool_output(req_id, str_result, cx)
-                    })
-                    .log_err();
+                    log.update(cx, |log, cx| log.set_tool_output(req_id, str_result, cx))
+                        .log_err();
 
                     result
                 })
@@ -188,7 +186,7 @@ impl EditToolRequest {
             cache: false,
         });
 
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let llm_request = LanguageModelRequest {
                 messages,
                 tools: vec![],
@@ -211,10 +209,10 @@ impl EditToolRequest {
             };
 
             while let Some(chunk) = chunks.stream.next().await {
-                request.process_response_chunk(&chunk?, &mut cx).await?;
+                request.process_response_chunk(&chunk?, cx).await?;
             }
 
-            request.finalize(&mut cx).await
+            request.finalize(cx).await
         })
     }
 

crates/assistant_tools/src/read_file_tool.rs 🔗

@@ -70,14 +70,14 @@ impl Tool for ReadFileTool {
             return Task::ready(Err(anyhow!("Path not found in project")));
         };
 
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let buffer = cx
                 .update(|cx| {
                     project.update(cx, |project, cx| project.open_buffer(project_path, cx))
                 })?
                 .await?;
 
-            let result = buffer.read_with(&cx, |buffer, _cx| {
+            let result = buffer.read_with(cx, |buffer, _cx| {
                 if buffer
                     .file()
                     .map_or(false, |file| file.disk_state().exists())
@@ -102,7 +102,7 @@ impl Tool for ReadFileTool {
                 }
             })??;
 
-            action_log.update(&mut cx, |log, cx| {
+            action_log.update(cx, |log, cx| {
                 log.buffer_read(buffer, cx);
             })?;
 

crates/assistant_tools/src/regex_search_tool.rs 🔗

@@ -73,7 +73,7 @@ impl Tool for RegexSearchTool {
 
         let results = project.update(cx, |project, cx| project.search(query, cx));
 
-        cx.spawn(|cx| async move {
+        cx.spawn(async move|cx|  {
             futures::pin_mut!(results);
 
             let mut output = String::new();
@@ -86,7 +86,7 @@ impl Tool for RegexSearchTool {
                     continue;
                 }
 
-                buffer.read_with(&cx, |buffer, cx| -> Result<(), anyhow::Error> {
+                buffer.read_with(cx, |buffer, cx| -> Result<(), anyhow::Error> {
                     if let Some(path) = buffer.file().map(|file| file.full_path(cx)) {
                         let mut file_header_written = false;
                         let mut ranges = ranges

crates/auto_update/src/auto_update.rs 🔗

@@ -252,11 +252,9 @@ impl AutoUpdater {
     }
 
     pub fn start_polling(&self, cx: &mut Context<Self>) -> Task<Result<()>> {
-        cx.spawn(|this, mut cx| async move {
-            loop {
-                this.update(&mut cx, |this, cx| this.poll(cx))?;
-                cx.background_executor().timer(POLL_INTERVAL).await;
-            }
+        cx.spawn(async move |this, cx| loop {
+            this.update(cx, |this, cx| this.poll(cx))?;
+            cx.background_executor().timer(POLL_INTERVAL).await;
         })
     }
 
@@ -267,9 +265,9 @@ impl AutoUpdater {
 
         cx.notify();
 
-        self.pending_poll = Some(cx.spawn(|this, mut cx| async move {
+        self.pending_poll = Some(cx.spawn(async move |this, cx| {
             let result = Self::update(this.upgrade()?, cx.clone()).await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.pending_poll = None;
                 if let Err(error) = result {
                     log::error!("auto-update failed: error:{:?}", error);

crates/auto_update_ui/src/auto_update_ui.rs 🔗

@@ -64,7 +64,7 @@ fn view_release_notes_locally(
 
     workspace
         .with_local_workspace(window, cx, move |_, window, cx| {
-            cx.spawn_in(window, |workspace, mut cx| async move {
+            cx.spawn_in(window, async move |workspace, cx| {
                 let markdown = markdown.await.log_err();
                 let response = client.get(&url, Default::default(), true).await;
                 let Some(mut response) = response.log_err() else {
@@ -79,7 +79,7 @@ fn view_release_notes_locally(
 
                 if let Ok(body) = body {
                     workspace
-                        .update_in(&mut cx, |workspace, window, cx| {
+                        .update_in(cx, |workspace, window, cx| {
                             let project = workspace.project().clone();
                             let buffer = project.update(cx, |project, cx| {
                                 project.create_local_buffer("", markdown, cx)
@@ -130,7 +130,7 @@ pub fn notify_if_app_was_updated(cx: &mut App) {
         return;
     };
     let should_show_notification = updater.read(cx).should_show_update_notification(cx);
-    cx.spawn(|cx| async move {
+    cx.spawn(async move |cx| {
         let should_show_notification = should_show_notification.await?;
         if should_show_notification {
             cx.update(|cx| {

crates/buffer_diff/src/buffer_diff.rs 🔗

@@ -1080,12 +1080,12 @@ impl BufferDiff {
         let complete_on_drop = util::defer(|| {
             tx.send(()).ok();
         });
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             let snapshot = snapshot.await;
             let Some(this) = this.upgrade() else {
                 return;
             };
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 this.set_state(snapshot, &buffer);
             })
             .log_err();

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

@@ -54,10 +54,10 @@ impl OneAtATime {
     {
         let (tx, rx) = oneshot::channel();
         self.cancel.replace(tx);
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             futures::select_biased! {
                 _ = rx.fuse() => Ok(None),
-                result = f(cx).fuse() => result.map(Some),
+                result = f(cx.clone()).fuse() => result.map(Some),
             }
         })
     }
@@ -192,19 +192,19 @@ impl ActiveCall {
         };
 
         let invite = if let Some(room) = room {
-            cx.spawn(move |_, mut cx| async move {
+            cx.spawn(async move |_, cx| {
                 let room = room.await.map_err(|err| anyhow!("{:?}", err))?;
 
                 let initial_project_id = if let Some(initial_project) = initial_project {
                     Some(
-                        room.update(&mut cx, |room, cx| room.share_project(initial_project, cx))?
+                        room.update(cx, |room, cx| room.share_project(initial_project, cx))?
                             .await?,
                     )
                 } else {
                     None
                 };
 
-                room.update(&mut cx, move |room, cx| {
+                room.update(cx, move |room, cx| {
                     room.call(called_user_id, initial_project_id, cx)
                 })?
                 .await?;
@@ -215,7 +215,7 @@ impl ActiveCall {
             let client = self.client.clone();
             let user_store = self.user_store.clone();
             let room = cx
-                .spawn(move |this, mut cx| async move {
+                .spawn(async move |this, cx| {
                     let create_room = async {
                         let room = cx
                             .update(|cx| {
@@ -229,14 +229,14 @@ impl ActiveCall {
                             })?
                             .await?;
 
-                        this.update(&mut cx, |this, cx| this.set_room(Some(room.clone()), cx))?
+                        this.update(cx, |this, cx| this.set_room(Some(room.clone()), cx))?
                             .await?;
 
                         anyhow::Ok(room)
                     };
 
                     let room = create_room.await;
-                    this.update(&mut cx, |this, _| this.pending_room_creation = None)?;
+                    this.update(cx, |this, _| this.pending_room_creation = None)?;
                     room.map_err(Arc::new)
                 })
                 .shared();
@@ -247,10 +247,10 @@ impl ActiveCall {
             })
         };
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = invite.await;
             if result.is_ok() {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.report_call_event("Participant Invited", cx)
                 })?;
             } else {
@@ -258,7 +258,7 @@ impl ActiveCall {
                 log::error!("invite failed: {:?}", result);
             }
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.pending_invites.remove(&called_user_id);
                 cx.notify();
             })?;
@@ -315,11 +315,11 @@ impl ActiveCall {
             ._join_debouncer
             .spawn(cx, move |cx| Room::join(room_id, client, user_store, cx));
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let room = join.await?;
-            this.update(&mut cx, |this, cx| this.set_room(room.clone(), cx))?
+            this.update(cx, |this, cx| this.set_room(room.clone(), cx))?
                 .await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.report_call_event("Incoming Call Accepted", cx)
             })?;
             Ok(())
@@ -363,13 +363,11 @@ impl ActiveCall {
             Room::join_channel(channel_id, client, user_store, cx).await
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let room = join.await?;
-            this.update(&mut cx, |this, cx| this.set_room(room.clone(), cx))?
+            this.update(cx, |this, cx| this.set_room(room.clone(), cx))?
                 .await?;
-            this.update(&mut cx, |this, cx| {
-                this.report_call_event("Channel Joined", cx)
-            })?;
+            this.update(cx, |this, cx| this.report_call_event("Channel Joined", cx))?;
             Ok(room)
         })
     }

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

@@ -128,7 +128,11 @@ impl Room {
 
         let maintain_connection = cx.spawn({
             let client = client.clone();
-            move |this, cx| Self::maintain_connection(this, client.clone(), cx).log_err()
+            async move |this, cx| {
+                Self::maintain_connection(this, client.clone(), cx)
+                    .log_err()
+                    .await
+            }
         });
 
         Audio::play_sound(Sound::Joined, cx);
@@ -172,7 +176,7 @@ impl Room {
         user_store: Entity<UserStore>,
         cx: &mut App,
     ) -> Task<Result<Entity<Self>>> {
-        cx.spawn(move |mut cx| async move {
+        cx.spawn(async move |cx| {
             let response = client.request(proto::CreateRoom {}).await?;
             let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
             let room = cx.new(|cx| {
@@ -192,7 +196,7 @@ impl Room {
 
             let initial_project_id = if let Some(initial_project) = initial_project {
                 let initial_project_id = room
-                    .update(&mut cx, |room, cx| {
+                    .update(cx, |room, cx| {
                         room.share_project(initial_project.clone(), cx)
                     })?
                     .await?;
@@ -202,7 +206,7 @@ impl Room {
             };
 
             let did_join = room
-                .update(&mut cx, |room, cx| {
+                .update(cx, |room, cx| {
                     room.leave_when_empty = true;
                     room.call(called_user_id, initial_project_id, cx)
                 })?
@@ -358,7 +362,7 @@ impl Room {
     async fn maintain_connection(
         this: WeakEntity<Self>,
         client: Arc<Client>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<()> {
         let mut client_status = client.status();
         loop {
@@ -370,7 +374,7 @@ impl Room {
 
                 this.upgrade()
                     .ok_or_else(|| anyhow!("room was dropped"))?
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         this.status = RoomStatus::Rejoining;
                         cx.notify();
                     })?;
@@ -386,7 +390,7 @@ impl Room {
                                 log::info!("client reconnected, attempting to rejoin room");
 
                                 let Some(this) = this.upgrade() else { break };
-                                match this.update(&mut cx, |this, cx| this.rejoin(cx)) {
+                                match this.update(cx, |this, cx| this.rejoin(cx)) {
                                     Ok(task) => {
                                         if task.await.log_err().is_some() {
                                             return true;
@@ -435,7 +439,7 @@ impl Room {
         // we leave the room and return an error.
         if let Some(this) = this.upgrade() {
             log::info!("reconnection failed, leaving room");
-            this.update(&mut cx, |this, cx| this.leave(cx))?.await?;
+            this.update(cx, |this, cx| this.leave(cx))?.await?;
         }
         Err(anyhow!(
             "can't reconnect to room: client failed to re-establish connection"
@@ -490,12 +494,12 @@ impl Room {
             rejoined_projects,
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = response.await?;
             let message_id = response.message_id;
             let response = response.payload;
             let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.status = RoomStatus::Online;
                 this.apply_room_update(room_proto, cx)?;
 
@@ -577,7 +581,7 @@ impl Room {
         let client = self.client.clone();
         let room_id = self.id;
         let role = role.into();
-        cx.spawn(|_, _| async move {
+        cx.spawn(async move |_, _| {
             client
                 .request(proto::SetRoomParticipantRole {
                     room_id,
@@ -709,11 +713,11 @@ impl Room {
                     user_store.get_users(pending_participant_user_ids, cx),
                 )
             });
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (remote_participants, pending_participants) =
                 futures::join!(remote_participants, pending_participants);
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.participant_user_ids.clear();
 
                 if let Some(participant) = local_participant {
@@ -1116,7 +1120,7 @@ impl Room {
         let client = self.client.clone();
         let room_id = self.id;
         self.pending_call_count += 1;
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = client
                 .request(proto::Call {
                     room_id,
@@ -1124,7 +1128,7 @@ impl Room {
                     initial_project_id,
                 })
                 .await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.pending_call_count -= 1;
                 if this.should_leave() {
                     this.leave(cx).detach_and_log_err(cx);
@@ -1145,11 +1149,11 @@ impl Room {
         let client = self.client.clone();
         let user_store = self.user_store.clone();
         cx.emit(Event::RemoteProjectJoined { project_id: id });
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let project =
                 Project::in_room(id, client, user_store, language_registry, fs, cx.clone()).await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.joined_projects.retain(|project| {
                     if let Some(project) = project.upgrade() {
                         !project.read(cx).is_disconnected(cx)
@@ -1178,15 +1182,13 @@ impl Room {
             is_ssh_project: project.read(cx).is_via_ssh(),
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = request.await?;
 
-            project.update(&mut cx, |project, cx| {
-                project.shared(response.project_id, cx)
-            })??;
+            project.update(cx, |project, cx| project.shared(response.project_id, cx))??;
 
             // If the user's location is in this project, it changes from UnsharedProject to SharedProject.
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.shared_projects.insert(project.downgrade());
                 let active_project = this.local_participant.active_project.as_ref();
                 if active_project.map_or(false, |location| *location == project) {
@@ -1342,7 +1344,7 @@ impl Room {
             return Task::ready(Err(anyhow!("live-kit was not initialized")));
         };
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (track, stream) = capture_local_audio_track(cx.background_executor())?.await;
 
             let publication = participant
@@ -1355,7 +1357,7 @@ impl Room {
                 )
                 .await
                 .map_err(|error| anyhow!("failed to publish track: {error}"));
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let live_kit = this
                     .live_kit
                     .as_mut()
@@ -1428,7 +1430,7 @@ impl Room {
 
         let sources = cx.screen_capture_sources();
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let sources = sources.await??;
             let source = sources.first().ok_or_else(|| anyhow!("no display found"))?;
 
@@ -1446,7 +1448,7 @@ impl Room {
                 .await
                 .map_err(|error| anyhow!("error publishing screen track {error:?}"));
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let live_kit = this
                     .live_kit
                     .as_mut()
@@ -1639,7 +1641,7 @@ fn spawn_room_connection(
     cx: &mut Context<'_, Room>,
 ) {
     if let Some(connection_info) = livekit_connection_info {
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (room, mut events) = livekit::Room::connect(
                 &connection_info.server_url,
                 &connection_info.token,
@@ -1647,11 +1649,11 @@ fn spawn_room_connection(
             )
             .await?;
 
-            this.update(&mut cx, |this, cx| {
-                let _handle_updates = cx.spawn(|this, mut cx| async move {
+            this.update(cx, |this, cx| {
+                let _handle_updates = cx.spawn(async move |this, cx| {
                     while let Some(event) = events.recv().await {
                         if this
-                            .update(&mut cx, |this, cx| {
+                            .update(cx, |this, cx| {
                                 this.livekit_room_updated(event, cx).warn_on_err();
                             })
                             .is_err()

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

@@ -47,10 +47,10 @@ impl OneAtATime {
     {
         let (tx, rx) = oneshot::channel();
         self.cancel.replace(tx);
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             futures::select_biased! {
                 _ = rx.fuse() => Ok(None),
-                result = f(cx).fuse() => result.map(Some),
+                result = f(cx.clone()).fuse() => result.map(Some),
             }
         })
     }
@@ -185,19 +185,19 @@ impl ActiveCall {
         };
 
         let invite = if let Some(room) = room {
-            cx.spawn(move |_, mut cx| async move {
+            cx.spawn(async move |_, cx| {
                 let room = room.await.map_err(|err| anyhow!("{:?}", err))?;
 
                 let initial_project_id = if let Some(initial_project) = initial_project {
                     Some(
-                        room.update(&mut cx, |room, cx| room.share_project(initial_project, cx))?
+                        room.update(cx, |room, cx| room.share_project(initial_project, cx))?
                             .await?,
                     )
                 } else {
                     None
                 };
 
-                room.update(&mut cx, move |room, cx| {
+                room.update(cx, move |room, cx| {
                     room.call(called_user_id, initial_project_id, cx)
                 })?
                 .await?;
@@ -208,7 +208,7 @@ impl ActiveCall {
             let client = self.client.clone();
             let user_store = self.user_store.clone();
             let room = cx
-                .spawn(move |this, mut cx| async move {
+                .spawn(async move |this, cx| {
                     let create_room = async {
                         let room = cx
                             .update(|cx| {
@@ -222,14 +222,14 @@ impl ActiveCall {
                             })?
                             .await?;
 
-                        this.update(&mut cx, |this, cx| this.set_room(Some(room.clone()), cx))?
+                        this.update(cx, |this, cx| this.set_room(Some(room.clone()), cx))?
                             .await?;
 
                         anyhow::Ok(room)
                     };
 
                     let room = create_room.await;
-                    this.update(&mut cx, |this, _| this.pending_room_creation = None)?;
+                    this.update(cx, |this, _| this.pending_room_creation = None)?;
                     room.map_err(Arc::new)
                 })
                 .shared();
@@ -240,10 +240,10 @@ impl ActiveCall {
             })
         };
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = invite.await;
             if result.is_ok() {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.report_call_event("Participant Invited", cx)
                 })?;
             } else {
@@ -251,7 +251,7 @@ impl ActiveCall {
                 log::error!("invite failed: {:?}", result);
             }
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.pending_invites.remove(&called_user_id);
                 cx.notify();
             })?;
@@ -304,15 +304,15 @@ impl ActiveCall {
         let room_id = call.room_id;
         let client = self.client.clone();
         let user_store = self.user_store.clone();
-        let join = self
-            ._join_debouncer
-            .spawn(cx, move |cx| Room::join(room_id, client, user_store, cx));
+        let join = self._join_debouncer.spawn(cx, move |mut cx| async move {
+            Room::join(room_id, client, user_store, &mut cx).await
+        });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let room = join.await?;
-            this.update(&mut cx, |this, cx| this.set_room(room.clone(), cx))?
+            this.update(cx, |this, cx| this.set_room(room.clone(), cx))?
                 .await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.report_call_event("Incoming Call Accepted", cx)
             })?;
             Ok(())
@@ -352,17 +352,15 @@ impl ActiveCall {
 
         let client = self.client.clone();
         let user_store = self.user_store.clone();
-        let join = self._join_debouncer.spawn(cx, move |cx| async move {
-            Room::join_channel(channel_id, client, user_store, cx).await
+        let join = self._join_debouncer.spawn(cx, move |mut cx| async move {
+            Room::join_channel(channel_id, client, user_store, &mut cx).await
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let room = join.await?;
-            this.update(&mut cx, |this, cx| this.set_room(room.clone(), cx))?
+            this.update(cx, |this, cx| this.set_room(room.clone(), cx))?
                 .await?;
-            this.update(&mut cx, |this, cx| {
-                this.report_call_event("Channel Joined", cx)
-            })?;
+            this.update(cx, |this, cx| this.report_call_event("Channel Joined", cx))?;
             Ok(room)
         })
     }

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

@@ -115,7 +115,7 @@ impl Room {
             let mut status = room.status();
             // Consume the initial status of the room.
             let _ = status.try_recv();
-            let _maintain_room = cx.spawn(|this, mut cx| async move {
+            let _maintain_room = cx.spawn(async move |this, cx| {
                 while let Some(status) = status.next().await {
                     let this = if let Some(this) = this.upgrade() {
                         this
@@ -124,8 +124,7 @@ impl Room {
                     };
 
                     if status == livekit_client_macos::ConnectionState::Disconnected {
-                        this.update(&mut cx, |this, cx| this.leave(cx).log_err())
-                            .ok();
+                        this.update(cx, |this, cx| this.leave(cx).log_err()).ok();
                         break;
                     }
                 }
@@ -133,7 +132,7 @@ impl Room {
 
             let _handle_updates = cx.spawn({
                 let room = room.clone();
-                move |this, mut cx| async move {
+                async move |this, cx| {
                     let mut updates = room.updates();
                     while let Some(update) = updates.next().await {
                         let this = if let Some(this) = this.upgrade() {
@@ -142,7 +141,7 @@ impl Room {
                             break;
                         };
 
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             this.live_kit_room_updated(update, cx).log_err()
                         })
                         .ok();
@@ -151,9 +150,9 @@ impl Room {
             });
 
             let connect = room.connect(&connection_info.server_url, &connection_info.token);
-            cx.spawn(|this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 connect.await?;
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     if this.can_use_microphone() {
                         if let Some(live_kit) = &this.live_kit {
                             if !live_kit.muted_by_user && !live_kit.deafened {
@@ -184,7 +183,11 @@ impl Room {
 
         let maintain_connection = cx.spawn({
             let client = client.clone();
-            move |this, cx| Self::maintain_connection(this, client.clone(), cx).log_err()
+            async move |this, cx| {
+                Self::maintain_connection(this, client.clone(), cx)
+                    .log_err()
+                    .await
+            }
         });
 
         Audio::play_sound(Sound::Joined, cx);
@@ -228,7 +231,7 @@ impl Room {
         user_store: Entity<UserStore>,
         cx: &mut App,
     ) -> Task<Result<Entity<Self>>> {
-        cx.spawn(move |mut cx| async move {
+        cx.spawn(async move |cx| {
             let response = client.request(proto::CreateRoom {}).await?;
             let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
             let room = cx.new(|cx| {
@@ -248,7 +251,7 @@ impl Room {
 
             let initial_project_id = if let Some(initial_project) = initial_project {
                 let initial_project_id = room
-                    .update(&mut cx, |room, cx| {
+                    .update(cx, |room, cx| {
                         room.share_project(initial_project.clone(), cx)
                     })?
                     .await?;
@@ -258,7 +261,7 @@ impl Room {
             };
 
             let did_join = room
-                .update(&mut cx, |room, cx| {
+                .update(cx, |room, cx| {
                     room.leave_when_empty = true;
                     room.call(called_user_id, initial_project_id, cx)
                 })?
@@ -274,7 +277,7 @@ impl Room {
         channel_id: ChannelId,
         client: Arc<Client>,
         user_store: Entity<UserStore>,
-        cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<Entity<Self>> {
         Self::from_join_response(
             client
@@ -292,7 +295,7 @@ impl Room {
         room_id: u64,
         client: Arc<Client>,
         user_store: Entity<UserStore>,
-        cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<Entity<Self>> {
         Self::from_join_response(
             client.request(proto::JoinRoom { id: room_id }).await?,
@@ -333,7 +336,7 @@ impl Room {
         response: proto::JoinRoomResponse,
         client: Arc<Client>,
         user_store: Entity<UserStore>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<Entity<Self>> {
         let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
         let room = cx.new(|cx| {
@@ -346,7 +349,7 @@ impl Room {
                 cx,
             )
         })?;
-        room.update(&mut cx, |room, cx| {
+        room.update(cx, |room, cx| {
             room.leave_when_empty = room.channel_id.is_none();
             room.apply_room_update(room_proto, cx)?;
             anyhow::Ok(())
@@ -414,7 +417,7 @@ impl Room {
     async fn maintain_connection(
         this: WeakEntity<Self>,
         client: Arc<Client>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<()> {
         let mut client_status = client.status();
         loop {
@@ -426,7 +429,7 @@ impl Room {
 
                 this.upgrade()
                     .ok_or_else(|| anyhow!("room was dropped"))?
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         this.status = RoomStatus::Rejoining;
                         cx.notify();
                     })?;
@@ -442,7 +445,7 @@ impl Room {
                                 log::info!("client reconnected, attempting to rejoin room");
 
                                 let Some(this) = this.upgrade() else { break };
-                                match this.update(&mut cx, |this, cx| this.rejoin(cx)) {
+                                match this.update(cx, |this, cx| this.rejoin(cx)) {
                                     Ok(task) => {
                                         if task.await.log_err().is_some() {
                                             return true;
@@ -491,7 +494,7 @@ impl Room {
         // we leave the room and return an error.
         if let Some(this) = this.upgrade() {
             log::info!("reconnection failed, leaving room");
-            this.update(&mut cx, |this, cx| this.leave(cx))?.await?;
+            this.update(cx, |this, cx| this.leave(cx))?.await?;
         }
         Err(anyhow!(
             "can't reconnect to room: client failed to re-establish connection"
@@ -546,12 +549,12 @@ impl Room {
             rejoined_projects,
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = response.await?;
             let message_id = response.message_id;
             let response = response.payload;
             let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.status = RoomStatus::Online;
                 this.apply_room_update(room_proto, cx)?;
 
@@ -633,7 +636,7 @@ impl Room {
         let client = self.client.clone();
         let room_id = self.id;
         let role = role.into();
-        cx.spawn(|_, _| async move {
+        cx.spawn(async move |_, _| {
             client
                 .request(proto::SetRoomParticipantRole {
                     room_id,
@@ -736,11 +739,11 @@ impl Room {
                 )
             });
 
-        self.pending_room_update = Some(cx.spawn(|this, mut cx| async move {
+        self.pending_room_update = Some(cx.spawn(async move |this, cx| {
             let (remote_participants, pending_participants) =
                 futures::join!(remote_participants, pending_participants);
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.participant_user_ids.clear();
 
                 if let Some(participant) = local_participant {
@@ -1136,7 +1139,7 @@ impl Room {
         let client = self.client.clone();
         let room_id = self.id;
         self.pending_call_count += 1;
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = client
                 .request(proto::Call {
                     room_id,
@@ -1144,7 +1147,7 @@ impl Room {
                     initial_project_id,
                 })
                 .await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.pending_call_count -= 1;
                 if this.should_leave() {
                     this.leave(cx).detach_and_log_err(cx);
@@ -1165,11 +1168,11 @@ impl Room {
         let client = self.client.clone();
         let user_store = self.user_store.clone();
         cx.emit(Event::RemoteProjectJoined { project_id: id });
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let project =
                 Project::in_room(id, client, user_store, language_registry, fs, cx.clone()).await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.joined_projects.retain(|project| {
                     if let Some(project) = project.upgrade() {
                         !project.read(cx).is_disconnected(cx)
@@ -1198,15 +1201,13 @@ impl Room {
             is_ssh_project: project.read(cx).is_via_ssh(),
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = request.await?;
 
-            project.update(&mut cx, |project, cx| {
-                project.shared(response.project_id, cx)
-            })??;
+            project.update(cx, |project, cx| project.shared(response.project_id, cx))??;
 
             // If the user's location is in this project, it changes from UnsharedProject to SharedProject.
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.shared_projects.insert(project.downgrade());
                 let active_project = this.local_participant.active_project.as_ref();
                 if active_project.map_or(false, |location| *location == project) {
@@ -1348,12 +1349,12 @@ impl Room {
             return Task::ready(Err(anyhow!("live-kit was not initialized")));
         };
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let publish_track = async {
                 let track = LocalAudioTrack::create();
                 this.upgrade()
                     .ok_or_else(|| anyhow!("room was dropped"))?
-                    .update(&mut cx, |this, _| {
+                    .update(cx, |this, _| {
                         this.live_kit
                             .as_ref()
                             .map(|live_kit| live_kit.room.publish_audio_track(track))
@@ -1364,7 +1365,7 @@ impl Room {
             let publication = publish_track.await;
             this.upgrade()
                 .ok_or_else(|| anyhow!("room was dropped"))?
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     let live_kit = this
                         .live_kit
                         .as_mut()
@@ -1424,7 +1425,7 @@ impl Room {
             return Task::ready(Err(anyhow!("live-kit was not initialized")));
         };
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let publish_track = async {
                 let displays = displays.await?;
                 let display = displays
@@ -1433,7 +1434,7 @@ impl Room {
                 let track = LocalVideoTrack::screen_share_for_display(display);
                 this.upgrade()
                     .ok_or_else(|| anyhow!("room was dropped"))?
-                    .update(&mut cx, |this, _| {
+                    .update(cx, |this, _| {
                         this.live_kit
                             .as_ref()
                             .map(|live_kit| live_kit.room.publish_video_track(track))
@@ -1445,7 +1446,7 @@ impl Room {
             let publication = publish_track.await;
             this.upgrade()
                 .ok_or_else(|| anyhow!("room was dropped"))?
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     let live_kit = this
                         .live_kit
                         .as_mut()

crates/channel/src/channel_buffer.rs 🔗

@@ -47,7 +47,7 @@ impl ChannelBuffer {
         client: Arc<Client>,
         user_store: Entity<UserStore>,
         channel_store: Entity<ChannelStore>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<Entity<Self>> {
         let response = client
             .request(proto::JoinChannelBuffer {
@@ -66,7 +66,7 @@ impl ChannelBuffer {
             let capability = channel_store.read(cx).channel_capability(channel.id);
             language::Buffer::remote(buffer_id, response.replica_id as u16, capability, base_text)
         })?;
-        buffer.update(&mut cx, |buffer, cx| buffer.apply_ops(operations, cx))?;
+        buffer.update(cx, |buffer, cx| buffer.apply_ops(operations, cx))?;
 
         let subscription = client.subscribe_to_entity(channel.id.0)?;
 
@@ -208,7 +208,7 @@ impl ChannelBuffer {
         let client = self.client.clone();
         let epoch = self.epoch();
 
-        self.acknowledge_task = Some(cx.spawn(move |_, cx| async move {
+        self.acknowledge_task = Some(cx.spawn(async move |_, cx| {
             cx.background_executor()
                 .timer(ACKNOWLEDGE_DEBOUNCE_INTERVAL)
                 .await;

crates/channel/src/channel_chat.rs 🔗

@@ -106,7 +106,7 @@ impl ChannelChat {
         channel_store: Entity<ChannelStore>,
         user_store: Entity<UserStore>,
         client: Arc<Client>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<Entity<Self>> {
         let channel_id = channel.id;
         let subscription = client.subscribe_to_entity(channel_id.0).unwrap();
@@ -132,7 +132,7 @@ impl ChannelChat {
                 last_acknowledged_id: None,
                 rng: StdRng::from_entropy(),
                 first_loaded_message_id: None,
-                _subscription: subscription.set_entity(&cx.entity(), &mut cx.to_async()),
+                _subscription: subscription.set_entity(&cx.entity(), &cx.to_async()),
             }
         })?;
         Self::handle_loaded_messages(
@@ -141,7 +141,7 @@ impl ChannelChat {
             client,
             response.messages,
             response.done,
-            &mut cx,
+            cx,
         )
         .await?;
         Ok(handle)
@@ -205,7 +205,7 @@ impl ChannelChat {
         let outgoing_messages_lock = self.outgoing_messages_lock.clone();
 
         // todo - handle messages that fail to send (e.g. >1024 chars)
-        Ok(cx.spawn(move |this, mut cx| async move {
+        Ok(cx.spawn(async move |this, cx| {
             let outgoing_message_guard = outgoing_messages_lock.lock().await;
             let request = rpc.request(proto::SendChannelMessage {
                 channel_id: channel_id.0,
@@ -218,8 +218,8 @@ impl ChannelChat {
             drop(outgoing_message_guard);
             let response = response.message.ok_or_else(|| anyhow!("invalid message"))?;
             let id = response.id;
-            let message = ChannelMessage::from_proto(response, &user_store, &mut cx).await?;
-            this.update(&mut cx, |this, cx| {
+            let message = ChannelMessage::from_proto(response, &user_store, cx).await?;
+            this.update(cx, |this, cx| {
                 this.insert_messages(SumTree::from_item(message, &()), cx);
                 if this.first_loaded_message_id.is_none() {
                     this.first_loaded_message_id = Some(id);
@@ -234,9 +234,9 @@ impl ChannelChat {
             channel_id: self.channel_id.0,
             message_id: id,
         });
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             response.await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.message_removed(id, cx);
             })?;
             Ok(())
@@ -266,7 +266,7 @@ impl ChannelChat {
             nonce: Some(nonce.into()),
             mentions: mentions_to_proto(&message.mentions),
         });
-        Ok(cx.spawn(move |_, _| async move {
+        Ok(cx.spawn(async move |_, _| {
             request.await?;
             Ok(())
         }))
@@ -281,7 +281,7 @@ impl ChannelChat {
         let user_store = self.user_store.clone();
         let channel_id = self.channel_id;
         let before_message_id = self.first_loaded_message_id()?;
-        Some(cx.spawn(move |this, mut cx| {
+        Some(cx.spawn(async move |this, cx| {
             async move {
                 let response = rpc
                     .request(proto::GetChannelMessages {
@@ -295,13 +295,14 @@ impl ChannelChat {
                     rpc,
                     response.messages,
                     response.done,
-                    &mut cx,
+                    cx,
                 )
                 .await?;
 
                 anyhow::Ok(())
             }
             .log_err()
+            .await
         }))
     }
 
@@ -439,7 +440,7 @@ impl ChannelChat {
         let user_store = self.user_store.clone();
         let rpc = self.rpc.clone();
         let channel_id = self.channel_id;
-        cx.spawn(move |this, mut cx| {
+        cx.spawn(async move |this, cx| {
             async move {
                 let response = rpc
                     .request(proto::JoinChannelChat {
@@ -452,11 +453,11 @@ impl ChannelChat {
                     rpc.clone(),
                     response.messages,
                     response.done,
-                    &mut cx,
+                    cx,
                 )
                 .await?;
 
-                let pending_messages = this.update(&mut cx, |this, _| {
+                let pending_messages = this.update(cx, |this, _| {
                     this.pending_messages().cloned().collect::<Vec<_>>()
                 })?;
 
@@ -472,10 +473,10 @@ impl ChannelChat {
                     let message = ChannelMessage::from_proto(
                         response.message.ok_or_else(|| anyhow!("invalid message"))?,
                         &user_store,
-                        &mut cx,
+                        cx,
                     )
                     .await?;
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.insert_messages(SumTree::from_item(message, &()), cx);
                     })?;
                 }
@@ -483,6 +484,7 @@ impl ChannelChat {
                 anyhow::Ok(())
             }
             .log_err()
+            .await
         })
         .detach();
     }

crates/channel/src/channel_store.rs 🔗

@@ -164,22 +164,22 @@ impl ChannelStore {
 
         let mut connection_status = client.status();
         let (update_channels_tx, mut update_channels_rx) = mpsc::unbounded();
-        let watch_connection_status = cx.spawn(|this, mut cx| async move {
+        let watch_connection_status = cx.spawn(async move |this, cx| {
             while let Some(status) = connection_status.next().await {
                 let this = this.upgrade()?;
                 match status {
                     client::Status::Connected { .. } => {
-                        this.update(&mut cx, |this, cx| this.handle_connect(cx))
+                        this.update(cx, |this, cx| this.handle_connect(cx))
                             .ok()?
                             .await
                             .log_err()?;
                     }
                     client::Status::SignedOut | client::Status::UpgradeRequired => {
-                        this.update(&mut cx, |this, cx| this.handle_disconnect(false, cx))
+                        this.update(cx, |this, cx| this.handle_disconnect(false, cx))
                             .ok();
                     }
                     _ => {
-                        this.update(&mut cx, |this, cx| this.handle_disconnect(true, cx))
+                        this.update(cx, |this, cx| this.handle_disconnect(true, cx))
                             .ok();
                     }
                 }
@@ -200,13 +200,12 @@ impl ChannelStore {
             _rpc_subscriptions: rpc_subscriptions,
             _watch_connection_status: watch_connection_status,
             disconnect_channel_buffers_task: None,
-            _update_channels: cx.spawn(|this, mut cx| async move {
+            _update_channels: cx.spawn(async move |this, cx| {
                 maybe!(async move {
                     while let Some(update_channels) = update_channels_rx.next().await {
                         if let Some(this) = this.upgrade() {
-                            let update_task = this.update(&mut cx, |this, cx| {
-                                this.update_channels(update_channels, cx)
-                            })?;
+                            let update_task = this
+                                .update(cx, |this, cx| this.update_channels(update_channels, cx))?;
                             if let Some(update_task) = update_task {
                                 update_task.await.log_err();
                             }
@@ -310,7 +309,9 @@ impl ChannelStore {
         self.open_channel_resource(
             channel_id,
             |this| &mut this.opened_buffers,
-            |channel, cx| ChannelBuffer::new(channel, client, user_store, channel_store, cx),
+            async move |channel, cx| {
+                ChannelBuffer::new(channel, client, user_store, channel_store, cx).await
+            },
             cx,
         )
     }
@@ -328,14 +329,14 @@ impl ChannelStore {
                     .request(proto::GetChannelMessagesById { message_ids }),
             )
         };
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             if let Some(request) = request {
                 let response = request.await?;
                 let this = this
                     .upgrade()
                     .ok_or_else(|| anyhow!("channel store dropped"))?;
-                let user_store = this.update(&mut cx, |this, _| this.user_store.clone())?;
-                ChannelMessage::from_proto_vec(response.messages, &user_store, &mut cx).await
+                let user_store = this.update(cx, |this, _| this.user_store.clone())?;
+                ChannelMessage::from_proto_vec(response.messages, &user_store, cx).await
             } else {
                 Ok(Vec::new())
             }
@@ -440,7 +441,7 @@ impl ChannelStore {
         self.open_channel_resource(
             channel_id,
             |this| &mut this.opened_chats,
-            |channel, cx| ChannelChat::new(channel, this, user_store, client, cx),
+            async move |channel, cx| ChannelChat::new(channel, this, user_store, client, cx).await,
             cx,
         )
     }
@@ -450,7 +451,7 @@ impl ChannelStore {
     /// Make sure that the resource is only opened once, even if this method
     /// is called multiple times with the same channel id while the first task
     /// is still running.
-    fn open_channel_resource<T, F, Fut>(
+    fn open_channel_resource<T, F>(
         &mut self,
         channel_id: ChannelId,
         get_map: fn(&mut Self) -> &mut HashMap<ChannelId, OpenEntityHandle<T>>,
@@ -458,8 +459,7 @@ impl ChannelStore {
         cx: &mut Context<Self>,
     ) -> Task<Result<Entity<T>>>
     where
-        F: 'static + FnOnce(Arc<Channel>, AsyncApp) -> Fut,
-        Fut: Future<Output = Result<Entity<T>>>,
+        F: AsyncFnOnce(Arc<Channel>, &mut AsyncApp) -> Result<Entity<T>> + 'static,
         T: 'static,
     {
         let task = loop {
@@ -479,8 +479,8 @@ impl ChannelStore {
                 },
                 hash_map::Entry::Vacant(e) => {
                     let task = cx
-                        .spawn(move |this, mut cx| async move {
-                            let channel = this.update(&mut cx, |this, _| {
+                        .spawn(async move |this, cx| {
+                            let channel = this.update(cx, |this, _| {
                                 this.channel_for_id(channel_id).cloned().ok_or_else(|| {
                                     Arc::new(anyhow!("no channel for id: {}", channel_id))
                                 })
@@ -493,9 +493,9 @@ impl ChannelStore {
                     e.insert(OpenEntityHandle::Loading(task.clone()));
                     cx.spawn({
                         let task = task.clone();
-                        move |this, mut cx| async move {
+                        async move |this, cx| {
                             let result = task.await;
-                            this.update(&mut cx, |this, _| match result {
+                            this.update(cx, |this, _| match result {
                                 Ok(model) => {
                                     get_map(this).insert(
                                         channel_id,
@@ -570,7 +570,7 @@ impl ChannelStore {
     ) -> Task<Result<ChannelId>> {
         let client = self.client.clone();
         let name = name.trim_start_matches('#').to_owned();
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = client
                 .request(proto::CreateChannel {
                     name,
@@ -583,7 +583,7 @@ impl ChannelStore {
                 .ok_or_else(|| anyhow!("missing channel in response"))?;
             let channel_id = ChannelId(channel.id);
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let task = this.update_channels(
                     proto::UpdateChannels {
                         channels: vec![channel],
@@ -611,7 +611,7 @@ impl ChannelStore {
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
         let client = self.client.clone();
-        cx.spawn(move |_, _| async move {
+        cx.spawn(async move |_, _| {
             let _ = client
                 .request(proto::MoveChannel {
                     channel_id: channel_id.0,
@@ -630,7 +630,7 @@ impl ChannelStore {
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
         let client = self.client.clone();
-        cx.spawn(move |_, _| async move {
+        cx.spawn(async move |_, _| {
             let _ = client
                 .request(proto::SetChannelVisibility {
                     channel_id: channel_id.0,
@@ -655,7 +655,7 @@ impl ChannelStore {
 
         cx.notify();
         let client = self.client.clone();
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = client
                 .request(proto::InviteChannelMember {
                     channel_id: channel_id.0,
@@ -664,7 +664,7 @@ impl ChannelStore {
                 })
                 .await;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.outgoing_invites.remove(&(channel_id, user_id));
                 cx.notify();
             })?;
@@ -687,7 +687,7 @@ impl ChannelStore {
 
         cx.notify();
         let client = self.client.clone();
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = client
                 .request(proto::RemoveChannelMember {
                     channel_id: channel_id.0,
@@ -695,7 +695,7 @@ impl ChannelStore {
                 })
                 .await;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.outgoing_invites.remove(&(channel_id, user_id));
                 cx.notify();
             })?;
@@ -717,7 +717,7 @@ impl ChannelStore {
 
         cx.notify();
         let client = self.client.clone();
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = client
                 .request(proto::SetChannelMemberRole {
                     channel_id: channel_id.0,
@@ -726,7 +726,7 @@ impl ChannelStore {
                 })
                 .await;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.outgoing_invites.remove(&(channel_id, user_id));
                 cx.notify();
             })?;
@@ -744,7 +744,7 @@ impl ChannelStore {
     ) -> Task<Result<()>> {
         let client = self.client.clone();
         let name = new_name.to_string();
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let channel = client
                 .request(proto::RenameChannel {
                     channel_id: channel_id.0,
@@ -753,7 +753,7 @@ impl ChannelStore {
                 .await?
                 .channel
                 .ok_or_else(|| anyhow!("missing channel in response"))?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let task = this.update_channels(
                     proto::UpdateChannels {
                         channels: vec![channel],
@@ -799,7 +799,7 @@ impl ChannelStore {
     ) -> Task<Result<Vec<ChannelMembership>>> {
         let client = self.client.clone();
         let user_store = self.user_store.downgrade();
-        cx.spawn(move |_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             let response = client
                 .request(proto::GetChannelMembers {
                     channel_id: channel_id.0,
@@ -807,7 +807,7 @@ impl ChannelStore {
                     limit: limit as u64,
                 })
                 .await?;
-            user_store.update(&mut cx, |user_store, _| {
+            user_store.update(cx, |user_store, _| {
                 user_store.insert(response.users);
                 response
                     .members
@@ -931,10 +931,10 @@ impl ChannelStore {
             buffers: buffer_versions,
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let mut response = response.await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.opened_buffers.retain(|_, buffer| match buffer {
                     OpenEntityHandle::Open(channel_buffer) => {
                         let Some(channel_buffer) = channel_buffer.upgrade() else {
@@ -1006,13 +1006,13 @@ impl ChannelStore {
         cx.notify();
         self.did_subscribe = false;
         self.disconnect_channel_buffers_task.get_or_insert_with(|| {
-            cx.spawn(move |this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 if wait_for_reconnect {
                     cx.background_executor().timer(RECONNECT_TIMEOUT).await;
                 }
 
                 if let Some(this) = this.upgrade() {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         for (_, buffer) in this.opened_buffers.drain() {
                             if let OpenEntityHandle::Open(buffer) = buffer {
                                 if let Some(buffer) = buffer.upgrade() {
@@ -1136,10 +1136,10 @@ impl ChannelStore {
         let users = self
             .user_store
             .update(cx, |user_store, cx| user_store.get_users(all_user_ids, cx));
-        Some(cx.spawn(|this, mut cx| async move {
+        Some(cx.spawn(async move |this, cx| {
             let users = users.await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 for entry in &channel_participants {
                     let mut participants: Vec<_> = entry
                         .participant_user_ids

crates/client/src/client.rs 🔗

@@ -144,9 +144,9 @@ pub fn init(client: &Arc<Client>, cx: &mut App) {
         let client = client.clone();
         move |_: &SignIn, cx| {
             if let Some(client) = client.upgrade() {
-                cx.spawn(
-                    |cx| async move { client.authenticate_and_connect(true, &cx).log_err().await },
-                )
+                cx.spawn(async move |cx| {
+                    client.authenticate_and_connect(true, &cx).log_err().await
+                })
                 .detach();
             }
         }
@@ -156,7 +156,7 @@ pub fn init(client: &Arc<Client>, cx: &mut App) {
         let client = client.clone();
         move |_: &SignOut, cx| {
             if let Some(client) = client.upgrade() {
-                cx.spawn(|cx| async move {
+                cx.spawn(async move |cx| {
                     client.sign_out(&cx).await;
                 })
                 .detach();
@@ -168,7 +168,7 @@ pub fn init(client: &Arc<Client>, cx: &mut App) {
         let client = client.clone();
         move |_: &Reconnect, cx| {
             if let Some(client) = client.upgrade() {
-                cx.spawn(|cx| async move {
+                cx.spawn(async move |cx| {
                     client.reconnect(&cx);
                 })
                 .detach();
@@ -640,7 +640,7 @@ impl Client {
             }
             Status::ConnectionLost => {
                 let this = self.clone();
-                state._reconnect_task = Some(cx.spawn(move |cx| async move {
+                state._reconnect_task = Some(cx.spawn(async move |cx| {
                     #[cfg(any(test, feature = "test-support"))]
                     let mut rng = StdRng::seed_from_u64(0);
                     #[cfg(not(any(test, feature = "test-support")))]
@@ -964,13 +964,11 @@ impl Client {
 
         cx.spawn({
             let this = self.clone();
-            |cx| {
-                async move {
-                    while let Some(message) = incoming.next().await {
-                        this.handle_message(message, &cx);
-                        // Don't starve the main thread when receiving lots of messages at once.
-                        smol::future::yield_now().await;
-                    }
+            async move |cx| {
+                while let Some(message) = incoming.next().await {
+                    this.handle_message(message, &cx);
+                    // Don't starve the main thread when receiving lots of messages at once.
+                    smol::future::yield_now().await;
                 }
             }
         })
@@ -978,23 +976,21 @@ impl Client {
 
         cx.spawn({
             let this = self.clone();
-            move |cx| async move {
-                match handle_io.await {
-                    Ok(()) => {
-                        if *this.status().borrow()
-                            == (Status::Connected {
-                                connection_id,
-                                peer_id,
-                            })
-                        {
-                            this.set_status(Status::SignedOut, &cx);
-                        }
-                    }
-                    Err(err) => {
-                        log::error!("connection error: {:?}", err);
-                        this.set_status(Status::ConnectionLost, &cx);
+            async move |cx| match handle_io.await {
+                Ok(()) => {
+                    if *this.status().borrow()
+                        == (Status::Connected {
+                            connection_id,
+                            peer_id,
+                        })
+                    {
+                        this.set_status(Status::SignedOut, &cx);
                     }
                 }
+                Err(err) => {
+                    log::error!("connection error: {:?}", err);
+                    this.set_status(Status::ConnectionLost, &cx);
+                }
             }
         })
         .detach();
@@ -1178,12 +1174,12 @@ impl Client {
     pub fn authenticate_with_browser(self: &Arc<Self>, cx: &AsyncApp) -> Task<Result<Credentials>> {
         let http = self.http.clone();
         let this = self.clone();
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             let background = cx.background_executor().clone();
 
             let (open_url_tx, open_url_rx) = oneshot::channel::<String>();
             cx.update(|cx| {
-                cx.spawn(move |cx| async move {
+                cx.spawn(async move |cx| {
                     let url = open_url_rx.await?;
                     cx.update(|cx| cx.open_url(&url))
                 })
@@ -1545,25 +1541,23 @@ impl Client {
                 original_sender_id,
                 type_name
             );
-            cx.spawn(move |_| async move {
-                match future.await {
-                    Ok(()) => {
-                        log::debug!(
-                            "rpc message handled. client_id:{}, sender_id:{:?}, type:{}",
-                            client_id,
-                            original_sender_id,
-                            type_name
-                        );
-                    }
-                    Err(error) => {
-                        log::error!(
-                            "error handling message. client_id:{}, sender_id:{:?}, type:{}, error:{:?}",
-                            client_id,
-                            original_sender_id,
-                            type_name,
-                            error
-                        );
-                    }
+            cx.spawn(async move |_| match future.await {
+                Ok(()) => {
+                    log::debug!(
+                        "rpc message handled. client_id:{}, sender_id:{:?}, type:{}",
+                        client_id,
+                        original_sender_id,
+                        type_name
+                    );
+                }
+                Err(error) => {
+                    log::error!(
+                        "error handling message. client_id:{}, sender_id:{:?}, type:{}, error:{:?}",
+                        client_id,
+                        original_sender_id,
+                        type_name,
+                        error
+                    );
                 }
             })
             .detach();

crates/client/src/test.rs 🔗

@@ -44,7 +44,7 @@ impl FakeServer {
                 let state = Arc::downgrade(&server.state);
                 move |cx| {
                     let state = state.clone();
-                    cx.spawn(move |_| async move {
+                    cx.spawn(async move |_| {
                         let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?;
                         let mut state = state.lock();
                         state.auth_count += 1;
@@ -63,7 +63,7 @@ impl FakeServer {
                     let peer = peer.clone();
                     let state = state.clone();
                     let credentials = credentials.clone();
-                    cx.spawn(move |cx| async move {
+                    cx.spawn(async move |cx| {
                         let state = state.upgrade().ok_or_else(|| anyhow!("server dropped"))?;
                         let peer = peer.upgrade().ok_or_else(|| anyhow!("server dropped"))?;
                         if state.lock().forbid_connections {

crates/client/src/user.rs 🔗

@@ -168,11 +168,10 @@ impl UserStore {
             invite_info: None,
             client: Arc::downgrade(&client),
             update_contacts_tx,
-            _maintain_contacts: cx.spawn(|this, mut cx| async move {
+            _maintain_contacts: cx.spawn(async move |this, cx| {
                 let _subscriptions = rpc_subscriptions;
                 while let Some(message) = update_contacts_rx.next().await {
-                    if let Ok(task) =
-                        this.update(&mut cx, |this, cx| this.update_contacts(message, cx))
+                    if let Ok(task) = this.update(cx, |this, cx| this.update_contacts(message, cx))
                     {
                         task.log_err().await;
                     } else {
@@ -180,7 +179,7 @@ impl UserStore {
                     }
                 }
             }),
-            _maintain_current_user: cx.spawn(|this, mut cx| async move {
+            _maintain_current_user: cx.spawn(async move |this, cx| {
                 let mut status = client.status();
                 let weak = Arc::downgrade(&client);
                 drop(client);
@@ -192,10 +191,9 @@ impl UserStore {
                     match status {
                         Status::Connected { .. } => {
                             if let Some(user_id) = client.user_id() {
-                                let fetch_user = if let Ok(fetch_user) = this
-                                    .update(&mut cx, |this, cx| {
-                                        this.get_user(user_id, cx).log_err()
-                                    }) {
+                                let fetch_user = if let Ok(fetch_user) =
+                                    this.update(cx, |this, cx| this.get_user(user_id, cx).log_err())
+                                {
                                     fetch_user
                                 } else {
                                     break;
@@ -239,12 +237,12 @@ impl UserStore {
 
                                 current_user_tx.send(user).await.ok();
 
-                                this.update(&mut cx, |_, cx| cx.notify())?;
+                                this.update(cx, |_, cx| cx.notify())?;
                             }
                         }
                         Status::SignedOut => {
                             current_user_tx.send(None).await.ok();
-                            this.update(&mut cx, |this, cx| {
+                            this.update(cx, |this, cx| {
                                 this.accepted_tos_at = None;
                                 cx.emit(Event::PrivateUserInfoUpdated);
                                 cx.notify();
@@ -253,7 +251,7 @@ impl UserStore {
                             .await;
                         }
                         Status::ConnectionLost => {
-                            this.update(&mut cx, |this, cx| {
+                            this.update(cx, |this, cx| {
                                 cx.notify();
                                 this.clear_contacts()
                             })?
@@ -350,7 +348,7 @@ impl UserStore {
                 user_ids.extend(message.outgoing_requests.iter());
 
                 let load_users = self.get_users(user_ids.into_iter().collect(), cx);
-                cx.spawn(|this, mut cx| async move {
+                cx.spawn(async move |this, cx| {
                     load_users.await?;
 
                     // Users are fetched in parallel above and cached in call to get_users
@@ -360,25 +358,22 @@ impl UserStore {
                         .upgrade()
                         .ok_or_else(|| anyhow!("can't upgrade user store handle"))?;
                     for contact in message.contacts {
-                        updated_contacts.push(Arc::new(
-                            Contact::from_proto(contact, &this, &mut cx).await?,
-                        ));
+                        updated_contacts
+                            .push(Arc::new(Contact::from_proto(contact, &this, cx).await?));
                     }
 
                     let mut incoming_requests = Vec::new();
                     for request in message.incoming_requests {
                         incoming_requests.push({
-                            this.update(&mut cx, |this, cx| {
-                                this.get_user(request.requester_id, cx)
-                            })?
-                            .await?
+                            this.update(cx, |this, cx| this.get_user(request.requester_id, cx))?
+                                .await?
                         });
                     }
 
                     let mut outgoing_requests = Vec::new();
                     for requested_user_id in message.outgoing_requests {
                         outgoing_requests.push(
-                            this.update(&mut cx, |this, cx| this.get_user(requested_user_id, cx))?
+                            this.update(cx, |this, cx| this.get_user(requested_user_id, cx))?
                                 .await?,
                         );
                     }
@@ -390,7 +385,7 @@ impl UserStore {
                     let removed_outgoing_requests =
                         HashSet::<u64>::from_iter(message.remove_outgoing_requests.iter().copied());
 
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         // Remove contacts
                         this.contacts
                             .retain(|contact| !removed_contacts.contains(&contact.user.id));
@@ -543,7 +538,7 @@ impl UserStore {
         cx: &Context<Self>,
     ) -> Task<Result<()>> {
         let client = self.client.upgrade();
-        cx.spawn(move |_, _| async move {
+        cx.spawn(async move |_, _| {
             client
                 .ok_or_else(|| anyhow!("can't upgrade client reference"))?
                 .request(proto::RespondToContactRequest {
@@ -565,12 +560,12 @@ impl UserStore {
         *self.pending_contact_requests.entry(user_id).or_insert(0) += 1;
         cx.notify();
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = client
                 .ok_or_else(|| anyhow!("can't upgrade client reference"))?
                 .request(request)
                 .await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 if let Entry::Occupied(mut request_count) =
                     this.pending_contact_requests.entry(user_id)
                 {
@@ -614,9 +609,9 @@ impl UserStore {
         let mut user_ids_to_fetch = user_ids.clone();
         user_ids_to_fetch.retain(|id| !self.users.contains_key(id));
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             if !user_ids_to_fetch.is_empty() {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.load_users(
                         proto::GetUsers {
                             user_ids: user_ids_to_fetch,
@@ -627,7 +622,7 @@ impl UserStore {
                 .await?;
             }
 
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 user_ids
                     .iter()
                     .map(|user_id| {
@@ -668,9 +663,9 @@ impl UserStore {
         }
 
         let load_users = self.get_users(vec![user_id], cx);
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             load_users.await?;
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 this.users
                     .get(&user_id)
                     .cloned()
@@ -708,14 +703,14 @@ impl UserStore {
         };
 
         let client = self.client.clone();
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             if let Some(client) = client.upgrade() {
                 let response = client
                     .request(proto::AcceptTermsOfService {})
                     .await
                     .context("error accepting tos")?;
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.set_current_user_accepted_tos_at(Some(response.accepted_tos_at));
                     cx.emit(Event::PrivateUserInfoUpdated);
                 })
@@ -737,12 +732,12 @@ impl UserStore {
         cx: &Context<Self>,
     ) -> Task<Result<Vec<Arc<User>>>> {
         let client = self.client.clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             if let Some(rpc) = client.upgrade() {
                 let response = rpc.request(request).await.context("error loading users")?;
                 let users = response.users;
 
-                this.update(&mut cx, |this, _| this.insert(users))
+                this.update(cx, |this, _| this.insert(users))
             } else {
                 Ok(Vec::new())
             }
@@ -796,8 +791,8 @@ impl UserStore {
         }
         if !missing_user_ids.is_empty() {
             let this = self.weak_self.clone();
-            cx.spawn(|mut cx| async move {
-                this.update(&mut cx, |this, cx| this.get_users(missing_user_ids, cx))?
+            cx.spawn(async move |cx| {
+                this.update(cx, |this, cx| this.get_users(missing_user_ids, cx))?
                     .await
             })
             .detach_and_log_err(cx);

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

@@ -562,7 +562,7 @@ async fn test_channel_buffers_and_server_restarts(
     deterministic.run_until_parked();
 
     // Client C can't reconnect.
-    client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
+    client_c.override_establish_connection(|_, cx| cx.spawn(async |_| future::pending().await));
 
     // Server stops.
     server.reset().await;

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

@@ -983,7 +983,7 @@ async fn test_server_restarts(
     server.reset().await;
 
     // Users A and B reconnect to the call. User C has troubles reconnecting, so it leaves the room.
-    client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
+    client_c.override_establish_connection(|_, cx| cx.spawn(async |_| future::pending().await));
     executor.advance_clock(RECONNECT_TIMEOUT);
     assert_eq!(
         room_participants(&room_a, cx_a),
@@ -1156,9 +1156,9 @@ async fn test_server_restarts(
     server.reset().await;
 
     // Users A and B have troubles reconnecting, so they leave the room.
-    client_a.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
-    client_b.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
-    client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending()));
+    client_a.override_establish_connection(|_, cx| cx.spawn(async |_| future::pending().await));
+    client_b.override_establish_connection(|_, cx| cx.spawn(async |_| future::pending().await));
+    client_c.override_establish_connection(|_, cx| cx.spawn(async |_| future::pending().await));
     executor.advance_clock(RECONNECT_TIMEOUT);
     assert_eq!(
         room_participants(&room_a, cx_a),

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

@@ -208,8 +208,8 @@ impl TestServer {
             .unwrap()
             .set_id(user_id.to_proto())
             .override_authenticate(move |cx| {
-                cx.spawn(|_| async move {
-                    let access_token = "the-token".to_string();
+                let access_token = "the-token".to_string();
+                cx.spawn(async move |_| {
                     Ok(Credentials {
                         user_id: user_id.to_proto(),
                         access_token,
@@ -230,7 +230,7 @@ impl TestServer {
                 let connection_killers = connection_killers.clone();
                 let forbid_connections = forbid_connections.clone();
                 let client_name = client_name.clone();
-                cx.spawn(move |cx| async move {
+                cx.spawn(async move |cx| {
                     if forbid_connections.load(SeqCst) {
                         Err(EstablishConnectionError::other(anyhow!(
                             "server is forbidding connections"

crates/collab_ui/src/channel_view.rs 🔗

@@ -64,9 +64,9 @@ impl ChannelView {
             window,
             cx,
         );
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let channel_view = channel_view.await?;
-            pane.update_in(&mut cx, |pane, window, cx| {
+            pane.update_in(cx, |pane, window, cx| {
                 telemetry::event!(
                     "Channel Notes Opened",
                     channel_id,
@@ -90,10 +90,10 @@ impl ChannelView {
         cx: &mut App,
     ) -> Task<Result<Entity<Self>>> {
         let channel_view = Self::load(channel_id, workspace, window, cx);
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let channel_view = channel_view.await?;
 
-            pane.update_in(&mut cx, |pane, window, cx| {
+            pane.update_in(cx, |pane, window, cx| {
                 let buffer_id = channel_view.read(cx).channel_buffer.read(cx).remote_id(cx);
 
                 let existing_view = pane
@@ -166,11 +166,11 @@ impl ChannelView {
         let channel_buffer =
             channel_store.update(cx, |store, cx| store.open_channel_buffer(channel_id, cx));
 
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let channel_buffer = channel_buffer.await?;
             let markdown = markdown.await.log_err();
 
-            channel_buffer.update(&mut cx, |channel_buffer, cx| {
+            channel_buffer.update(cx, |channel_buffer, cx| {
                 channel_buffer.buffer().update(cx, |buffer, cx| {
                     buffer.set_language_registry(language_registry);
                     let Some(markdown) = markdown else {
@@ -583,10 +583,10 @@ impl FollowableItem for ChannelView {
 
         let open = ChannelView::load(ChannelId(state.channel_id), workspace, window, cx);
 
-        Some(window.spawn(cx, |mut cx| async move {
+        Some(window.spawn(cx, async move |cx| {
             let this = open.await?;
 
-            let task = this.update_in(&mut cx, |this, window, cx| {
+            let task = this.update_in(cx, |this, window, cx| {
                 this.remote_id = Some(remote_id);
 
                 if let Some(state) = state.editor {

crates/collab_ui/src/chat_panel.rs 🔗

@@ -199,7 +199,7 @@ impl ChatPanel {
         workspace: WeakEntity<Workspace>,
         cx: AsyncWindowContext,
     ) -> Task<Result<Entity<Self>>> {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let serialized_panel = if let Some(panel) = cx
                 .background_spawn(async move { KEY_VALUE_STORE.read_kvp(CHAT_PANEL_KEY) })
                 .await
@@ -211,7 +211,7 @@ impl ChatPanel {
                 None
             };
 
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 let panel = Self::new(workspace, window, cx);
                 if let Some(serialized_panel) = serialized_panel {
                     panel.update(cx, |panel, cx| {
@@ -867,10 +867,10 @@ impl ChatPanel {
                 })
             });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let chat = open_chat.await?;
             let highlight_message_id = scroll_to_message_id;
-            let scroll_to_message_id = this.update(&mut cx, |this, cx| {
+            let scroll_to_message_id = this.update(cx, |this, cx| {
                 this.set_active_chat(chat.clone(), cx);
 
                 scroll_to_message_id.or(this.last_acknowledged_message_id)
@@ -881,11 +881,11 @@ impl ChatPanel {
                     ChannelChat::load_history_since_message(chat.clone(), message_id, cx.clone())
                         .await
                 {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         if let Some(highlight_message_id) = highlight_message_id {
-                            let task = cx.spawn(|this, mut cx| async move {
+                            let task = cx.spawn(async move |this, cx| {
                                 cx.background_executor().timer(Duration::from_secs(2)).await;
-                                this.update(&mut cx, |this, cx| {
+                                this.update(cx, |this, cx| {
                                     this.highlighted_message.take();
                                     cx.notify();
                                 })

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

@@ -137,11 +137,9 @@ impl MessageEditor {
         .detach();
 
         let markdown = language_registry.language_for_name("Markdown");
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             let markdown = markdown.await.context("failed to load Markdown language")?;
-            buffer.update(&mut cx, |buffer, cx| {
-                buffer.set_language(Some(markdown), cx)
-            })
+            buffer.update(cx, |buffer, cx| buffer.set_language(Some(markdown), cx))
         })
         .detach_and_log_err(cx);
 
@@ -232,7 +230,7 @@ impl MessageEditor {
     ) {
         if let language::BufferEvent::Reparsed | language::BufferEvent::Edited = event {
             let buffer = buffer.read(cx).snapshot();
-            self.mentions_task = Some(cx.spawn_in(window, |this, cx| async move {
+            self.mentions_task = Some(cx.spawn_in(window, async move |this, cx| {
                 cx.background_executor()
                     .timer(MENTIONS_DEBOUNCE_INTERVAL)
                     .await;
@@ -251,7 +249,7 @@ impl MessageEditor {
             self.collect_mention_candidates(buffer, end_anchor, cx)
         {
             if !candidates.is_empty() {
-                return cx.spawn(|_, cx| async move {
+                return cx.spawn(async move |_, cx| {
                     Ok(Some(
                         Self::resolve_completions_for_candidates(
                             &cx,
@@ -270,7 +268,7 @@ impl MessageEditor {
             self.collect_emoji_candidates(buffer, end_anchor, cx)
         {
             if !candidates.is_empty() {
-                return cx.spawn(|_, cx| async move {
+                return cx.spawn(async move |_, cx| {
                     Ok(Some(
                         Self::resolve_completions_for_candidates(
                             &cx,
@@ -453,7 +451,7 @@ impl MessageEditor {
     async fn find_mentions(
         this: WeakEntity<MessageEditor>,
         buffer: BufferSnapshot,
-        mut cx: AsyncWindowContext,
+        cx: &mut AsyncWindowContext,
     ) {
         let (buffer, ranges) = cx
             .background_spawn(async move {
@@ -462,7 +460,7 @@ impl MessageEditor {
             })
             .await;
 
-        this.update(&mut cx, |this, cx| {
+        this.update(cx, |this, cx| {
             let mut anchor_ranges = Vec::new();
             let mut mentioned_user_ids = Vec::new();
             let mut text = String::new();

crates/collab_ui/src/collab_panel.rs 🔗

@@ -1569,9 +1569,9 @@ impl CollabPanel {
                         channel_store.create_channel(&channel_name, *location, cx)
                     });
                     if location.is_none() {
-                        cx.spawn_in(window, |this, mut cx| async move {
+                        cx.spawn_in(window, async move |this, cx| {
                             let channel_id = create.await?;
-                            this.update_in(&mut cx, |this, window, cx| {
+                            this.update_in(cx, |this, window, cx| {
                                 this.show_channel_modal(
                                     channel_id,
                                     channel_modal::Mode::InviteMembers,
@@ -1944,8 +1944,8 @@ impl CollabPanel {
         let user_store = self.user_store.clone();
         let channel_store = self.channel_store.clone();
 
-        cx.spawn_in(window, |_, mut cx| async move {
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+        cx.spawn_in(window, async move |_, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 workspace.toggle_modal(window, cx, |window, cx| {
                     ChannelModal::new(
                         user_store.clone(),
@@ -1976,11 +1976,11 @@ impl CollabPanel {
             &["Leave", "Cancel"],
             cx,
         );
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             if answer.await? != 0 {
                 return Ok(());
             }
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.channel_store.update(cx, |channel_store, cx| {
                     channel_store.remove_member(channel_id, user_id, cx)
                 })
@@ -2009,13 +2009,13 @@ impl CollabPanel {
                 &["Remove", "Cancel"],
                 cx,
             );
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 if answer.await? == 0 {
                     channel_store
-                        .update(&mut cx, |channels, _| channels.remove_channel(channel_id))?
+                        .update(cx, |channels, _| channels.remove_channel(channel_id))?
                         .await
-                        .notify_async_err(&mut cx);
-                    this.update_in(&mut cx, |_, window, cx| cx.focus_self(window))
+                        .notify_async_err(cx);
+                    this.update_in(cx, |_, window, cx| cx.focus_self(window))
                         .ok();
                 }
                 anyhow::Ok(())
@@ -2043,12 +2043,12 @@ impl CollabPanel {
             &["Remove", "Cancel"],
             cx,
         );
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             if answer.await? == 0 {
                 user_store
-                    .update(&mut cx, |store, cx| store.remove_contact(user_id, cx))?
+                    .update(cx, |store, cx| store.remove_contact(user_id, cx))?
                     .await
-                    .notify_async_err(&mut cx);
+                    .notify_async_err(cx);
             }
             anyhow::Ok(())
         })
@@ -2161,11 +2161,11 @@ impl CollabPanel {
                             .full_width()
                             .on_click(cx.listener(|this, _, window, cx| {
                                 let client = this.client.clone();
-                                cx.spawn_in(window, |_, mut cx| async move {
+                                cx.spawn_in(window, async move |_, cx| {
                                     client
                                         .authenticate_and_connect(true, &cx)
                                         .await
-                                        .notify_async_err(&mut cx);
+                                        .notify_async_err(cx);
                                 })
                                 .detach()
                             })),

crates/collab_ui/src/collab_panel/channel_modal.rs 🔗

@@ -300,9 +300,9 @@ impl PickerDelegate for ChannelModalDelegate {
                         cx.background_executor().clone(),
                     ));
 
-                    cx.spawn_in(window, |picker, mut cx| async move {
+                    cx.spawn_in(window, async move |picker, cx| {
                         picker
-                            .update(&mut cx, |picker, cx| {
+                            .update(cx, |picker, cx| {
                                 let delegate = &mut picker.delegate;
                                 delegate.matching_member_indices.clear();
                                 delegate
@@ -316,10 +316,10 @@ impl PickerDelegate for ChannelModalDelegate {
                     let search_members = self.channel_store.update(cx, |store, cx| {
                         store.fuzzy_search_members(self.channel_id, query.clone(), 100, cx)
                     });
-                    cx.spawn_in(window, |picker, mut cx| async move {
+                    cx.spawn_in(window, async move |picker, cx| {
                         async {
                             let members = search_members.await?;
-                            picker.update(&mut cx, |picker, cx| {
+                            picker.update(cx, |picker, cx| {
                                 picker.delegate.has_all_members =
                                     query.is_empty() && members.len() < 100;
                                 picker.delegate.matching_member_indices =
@@ -338,10 +338,10 @@ impl PickerDelegate for ChannelModalDelegate {
                 let search_users = self
                     .user_store
                     .update(cx, |store, cx| store.fuzzy_search_users(query, cx));
-                cx.spawn_in(window, |picker, mut cx| async move {
+                cx.spawn_in(window, async move |picker, cx| {
                     async {
                         let users = search_users.await?;
-                        picker.update(&mut cx, |picker, cx| {
+                        picker.update(cx, |picker, cx| {
                             picker.delegate.matching_users = users;
                             cx.notify();
                         })?;
@@ -489,9 +489,9 @@ impl ChannelModalDelegate {
         let update = self.channel_store.update(cx, |store, cx| {
             store.set_member_role(self.channel_id, user_id, new_role, cx)
         });
-        cx.spawn_in(window, |picker, mut cx| async move {
+        cx.spawn_in(window, async move |picker, cx| {
             update.await?;
-            picker.update_in(&mut cx, |picker, window, cx| {
+            picker.update_in(cx, |picker, window, cx| {
                 let this = &mut picker.delegate;
                 if let Some(member) = this.members.iter_mut().find(|m| m.user.id == user_id) {
                     member.role = new_role;
@@ -513,9 +513,9 @@ impl ChannelModalDelegate {
         let update = self.channel_store.update(cx, |store, cx| {
             store.remove_member(self.channel_id, user_id, cx)
         });
-        cx.spawn_in(window, |picker, mut cx| async move {
+        cx.spawn_in(window, async move |picker, cx| {
             update.await?;
-            picker.update_in(&mut cx, |picker, window, cx| {
+            picker.update_in(cx, |picker, window, cx| {
                 let this = &mut picker.delegate;
                 if let Some(ix) = this.members.iter_mut().position(|m| m.user.id == user_id) {
                     this.members.remove(ix);
@@ -551,10 +551,10 @@ impl ChannelModalDelegate {
             store.invite_member(self.channel_id, user.id, ChannelRole::Member, cx)
         });
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             invite_member.await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let new_member = ChannelMembership {
                     user,
                     kind: proto::channel_member::Kind::Invitee,

crates/collab_ui/src/collab_panel/contact_finder.rs 🔗

@@ -102,10 +102,10 @@ impl PickerDelegate for ContactFinderDelegate {
             .user_store
             .update(cx, |store, cx| store.fuzzy_search_users(query, cx));
 
-        cx.spawn_in(window, |picker, mut cx| async move {
+        cx.spawn_in(window, async move |picker, cx| {
             async {
                 let potential_contacts = search_users.await?;
-                picker.update(&mut cx, |picker, cx| {
+                picker.update(cx, |picker, cx| {
                     picker.delegate.potential_contacts = potential_contacts.into();
                     cx.notify();
                 })?;

crates/collab_ui/src/notification_panel.rs 🔗

@@ -96,10 +96,10 @@ impl NotificationPanel {
 
         cx.new(|cx| {
             let mut status = client.status();
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 while (status.next().await).is_some() {
                     if this
-                        .update(&mut cx, |_: &mut Self, cx| {
+                        .update(cx, |_: &mut Self, cx| {
                             cx.notify();
                         })
                         .is_err()
@@ -181,7 +181,7 @@ impl NotificationPanel {
         workspace: WeakEntity<Workspace>,
         cx: AsyncWindowContext,
     ) -> Task<Result<Entity<Self>>> {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let serialized_panel = if let Some(panel) = cx
                 .background_spawn(async move { KEY_VALUE_STORE.read_kvp(NOTIFICATION_PANEL_KEY) })
                 .await
@@ -193,7 +193,7 @@ impl NotificationPanel {
                 None
             };
 
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 let panel = Self::new(workspace, window, cx);
                 if let Some(serialized_panel) = serialized_panel {
                     panel.update(cx, |panel, cx| {
@@ -445,12 +445,12 @@ impl NotificationPanel {
                 .entry(notification_id)
                 .or_insert_with(|| {
                     let client = self.client.clone();
-                    cx.spawn_in(window, |this, mut cx| async move {
+                    cx.spawn_in(window, async move |this, cx| {
                         cx.background_executor().timer(MARK_AS_READ_DELAY).await;
                         client
                             .request(proto::MarkNotificationRead { notification_id })
                             .await?;
-                        this.update(&mut cx, |this, _| {
+                        this.update(cx, |this, _| {
                             this.mark_as_read_tasks.remove(&notification_id);
                         })?;
                         Ok(())
@@ -556,9 +556,9 @@ impl NotificationPanel {
         let notification_id = entry.id;
         self.current_notification_toast = Some((
             notification_id,
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 cx.background_executor().timer(TOAST_DURATION).await;
-                this.update(&mut cx, |this, cx| this.remove_toast(notification_id, cx))
+                this.update(cx, |this, cx| this.remove_toast(notification_id, cx))
                     .ok();
             }),
         ));
@@ -643,7 +643,7 @@ impl Render for NotificationPanel {
                                         move |_, window, cx| {
                                             let client = client.clone();
                                             window
-                                                .spawn(cx, move |cx| async move {
+                                                .spawn(cx, async move |cx| {
                                                     client
                                                         .authenticate_and_connect(true, &cx)
                                                         .log_err()

crates/collab_ui/src/notifications/incoming_call_notification.rs 🔗

@@ -12,12 +12,12 @@ use workspace::AppState;
 pub fn init(app_state: &Arc<AppState>, cx: &mut App) {
     let app_state = Arc::downgrade(app_state);
     let mut incoming_call = ActiveCall::global(cx).read(cx).incoming();
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         let mut notification_windows: Vec<WindowHandle<IncomingCallNotification>> = Vec::new();
         while let Some(incoming_call) = incoming_call.next().await {
             for window in notification_windows.drain(..) {
                 window
-                    .update(&mut cx, |_, window, _| {
+                    .update(cx, |_, window, _| {
                         window.remove_window();
                     })
                     .log_err();
@@ -75,7 +75,7 @@ impl IncomingCallNotificationState {
             let initial_project_id = self.call.initial_project.as_ref().map(|project| project.id);
             let app_state = self.app_state.clone();
             let cx: &mut App = cx;
-            cx.spawn(|cx| async move {
+            cx.spawn(async move |cx| {
                 join.await?;
                 if let Some(project_id) = initial_project_id {
                     cx.update(|cx| {

crates/command_palette/src/command_palette.rs 🔗

@@ -327,13 +327,13 @@ impl PickerDelegate for CommandPaletteDelegate {
         });
         self.updating_matches = Some((task, rx.clone()));
 
-        cx.spawn_in(window, move |picker, mut cx| async move {
+        cx.spawn_in(window, async move |picker, cx| {
             let Some((commands, matches)) = rx.recv().await else {
                 return;
             };
 
             picker
-                .update(&mut cx, |picker, cx| {
+                .update(cx, |picker, cx| {
                     picker
                         .delegate
                         .matches_updated(query, commands, matches, cx)

crates/component_preview/src/component_preview.rs 🔗

@@ -560,7 +560,7 @@ impl SerializableItem for ComponentPreview {
         let user_store = project.read(cx).user_store().clone();
         let language_registry = project.read(cx).languages().clone();
 
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let user_store = user_store.clone();
             let language_registry = language_registry.clone();
             let weak_workspace = workspace.clone();

crates/context_server/src/client.rs 🔗

@@ -171,13 +171,17 @@ impl Client {
             let notification_handlers = notification_handlers.clone();
             let response_handlers = response_handlers.clone();
             let transport = transport.clone();
-            move |cx| {
+            async move |cx| {
                 Self::handle_input(transport, notification_handlers, response_handlers, cx)
                     .log_err()
+                    .await
             }
         });
-        let stderr_input_task = cx.spawn(|_| Self::handle_stderr(transport.clone()).log_err());
-        let input_task = cx.spawn(|_| async move {
+        let stderr_input_task = cx.spawn({
+            let transport = transport.clone();
+            async move |_| Self::handle_stderr(transport).log_err().await
+        });
+        let input_task = cx.spawn(async move |_| {
             let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task);
             stdout.or(stderr)
         });
@@ -217,7 +221,7 @@ impl Client {
         transport: Arc<dyn Transport>,
         notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
         response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
-        cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> anyhow::Result<()> {
         let mut receiver = transport.receive();
 

crates/context_server/src/extension_context_server.rs 🔗

@@ -41,16 +41,15 @@ impl ExtensionContextServerProxy for ContextServerFactoryRegistryProxy {
 
                             let id = id.clone();
                             let extension = extension.clone();
-                            cx.spawn(|mut cx| async move {
-                                let extension_project =
-                                    project.update(&mut cx, |project, cx| {
-                                        Arc::new(ExtensionProject {
-                                            worktree_ids: project
-                                                .visible_worktrees(cx)
-                                                .map(|worktree| worktree.read(cx).id().to_proto())
-                                                .collect(),
-                                        })
-                                    })?;
+                            cx.spawn(async move |cx| {
+                                let extension_project = project.update(cx, |project, cx| {
+                                    Arc::new(ExtensionProject {
+                                        worktree_ids: project
+                                            .visible_worktrees(cx)
+                                            .map(|worktree| worktree.read(cx).id().to_proto())
+                                            .collect(),
+                                    })
+                                })?;
 
                                 let command = extension
                                     .context_server_command(id.clone(), extension_project)

crates/context_server/src/manager.rs 🔗

@@ -147,14 +147,14 @@ impl ContextServerManager {
         if self.update_servers_task.is_some() {
             self.needs_server_update = true;
         } else {
-            self.update_servers_task = Some(cx.spawn(|this, mut cx| async move {
-                this.update(&mut cx, |this, _| {
+            self.update_servers_task = Some(cx.spawn(async move |this, cx| {
+                this.update(cx, |this, _| {
                     this.needs_server_update = false;
                 })?;
 
-                Self::maintain_servers(this.clone(), cx.clone()).await?;
+                Self::maintain_servers(this.clone(), cx).await?;
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     let has_any_context_servers = !this.servers().is_empty();
                     if has_any_context_servers {
                         CommandPaletteFilter::update_global(cx, |filter, _cx| {
@@ -186,13 +186,13 @@ impl ContextServerManager {
         cx: &mut Context<Self>,
     ) -> Task<anyhow::Result<()>> {
         let id = id.clone();
-        cx.spawn(|this, mut cx| async move {
-            if let Some(server) = this.update(&mut cx, |this, _cx| this.servers.remove(&id))? {
+        cx.spawn(async move |this, cx| {
+            if let Some(server) = this.update(cx, |this, _cx| this.servers.remove(&id))? {
                 server.stop()?;
                 let config = server.config();
                 let new_server = Arc::new(ContextServer::new(id.clone(), config));
                 new_server.clone().start(&cx).await?;
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.servers.insert(id.clone(), new_server);
                     cx.emit(Event::ServerStopped {
                         server_id: id.clone(),
@@ -214,10 +214,10 @@ impl ContextServerManager {
             .collect()
     }
 
-    async fn maintain_servers(this: WeakEntity<Self>, mut cx: AsyncApp) -> Result<()> {
+    async fn maintain_servers(this: WeakEntity<Self>, cx: &mut AsyncApp) -> Result<()> {
         let mut desired_servers = HashMap::default();
 
-        let (registry, project) = this.update(&mut cx, |this, cx| {
+        let (registry, project) = this.update(cx, |this, cx| {
             let location = this.project.read(cx).worktrees(cx).next().map(|worktree| {
                 settings::SettingsLocation {
                     worktree_id: worktree.read(cx).id(),
@@ -231,7 +231,7 @@ impl ContextServerManager {
         })?;
 
         for (id, factory) in
-            registry.read_with(&cx, |registry, _| registry.context_server_factories())?
+            registry.read_with(cx, |registry, _| registry.context_server_factories())?
         {
             let config = desired_servers.entry(id).or_default();
             if config.command.is_none() {
@@ -244,7 +244,7 @@ impl ContextServerManager {
         let mut servers_to_start = HashMap::default();
         let mut servers_to_stop = HashMap::default();
 
-        this.update(&mut cx, |this, _cx| {
+        this.update(cx, |this, _cx| {
             this.servers.retain(|id, server| {
                 if desired_servers.contains_key(id) {
                     true
@@ -270,16 +270,12 @@ impl ContextServerManager {
 
         for (id, server) in servers_to_stop {
             server.stop().log_err();
-            this.update(&mut cx, |_, cx| {
-                cx.emit(Event::ServerStopped { server_id: id })
-            })?;
+            this.update(cx, |_, cx| cx.emit(Event::ServerStopped { server_id: id }))?;
         }
 
         for (id, server) in servers_to_start {
             if server.start(&cx).await.log_err().is_some() {
-                this.update(&mut cx, |_, cx| {
-                    cx.emit(Event::ServerStarted { server_id: id })
-                })?;
+                this.update(cx, |_, cx| cx.emit(Event::ServerStarted { server_id: id }))?;
             }
         }
 

crates/context_server/src/transport/stdio_transport.rs 🔗

@@ -47,13 +47,13 @@ impl StdioTransport {
         let (stdout_sender, stdout_receiver) = channel::unbounded::<String>();
         let (stderr_sender, stderr_receiver) = channel::unbounded::<String>();
 
-        cx.spawn(|_| Self::handle_output(stdin, stdout_receiver).log_err())
+        cx.spawn(async move |_| Self::handle_output(stdin, stdout_receiver).log_err().await)
             .detach();
 
-        cx.spawn(|_| async move { Self::handle_input(stdout, stdin_sender).await })
+        cx.spawn(async move |_| Self::handle_input(stdout, stdin_sender).await)
             .detach();
 
-        cx.spawn(|_| async move { Self::handle_err(stderr, stderr_sender).await })
+        cx.spawn(async move |_| Self::handle_err(stderr, stderr_sender).await)
             .detach();
 
         Ok(Self {

crates/copilot/src/copilot.rs 🔗

@@ -226,17 +226,17 @@ impl RegisteredBuffer {
             let id = buffer.entity_id();
             let prev_pending_change =
                 mem::replace(&mut self.pending_buffer_change, Task::ready(None));
-            self.pending_buffer_change = cx.spawn(move |copilot, mut cx| async move {
+            self.pending_buffer_change = cx.spawn(async move |copilot, cx| {
                 prev_pending_change.await;
 
                 let old_version = copilot
-                    .update(&mut cx, |copilot, _| {
+                    .update(cx, |copilot, _| {
                         let server = copilot.server.as_authenticated().log_err()?;
                         let buffer = server.registered_buffers.get_mut(&id)?;
                         Some(buffer.snapshot.version.clone())
                     })
                     .ok()??;
-                let new_snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot()).ok()?;
+                let new_snapshot = buffer.update(cx, |buffer, _| buffer.snapshot()).ok()?;
 
                 let content_changes = cx
                     .background_spawn({
@@ -265,7 +265,7 @@ impl RegisteredBuffer {
                     .await;
 
                 copilot
-                    .update(&mut cx, |copilot, _| {
+                    .update(cx, |copilot, _| {
                         let server = copilot.server.as_authenticated().log_err()?;
                         let buffer = server.registered_buffers.get_mut(&id)?;
                         if !content_changes.is_empty() {
@@ -388,7 +388,7 @@ impl Copilot {
         let node_runtime = self.node_runtime.clone();
         let env = self.build_env(&language_settings.edit_predictions.copilot);
         let start_task = cx
-            .spawn(move |this, cx| {
+            .spawn(async move |this, cx| {
                 Self::start_language_server(
                     server_id,
                     http,
@@ -398,6 +398,7 @@ impl Copilot {
                     awaiting_sign_in_after_start,
                     cx,
                 )
+                .await
             })
             .shared();
         self.server = CopilotServer::Starting { task: start_task };
@@ -442,7 +443,7 @@ impl Copilot {
             },
             "copilot".into(),
             Default::default(),
-            cx.to_async(),
+            &mut cx.to_async(),
         );
         let http = http_client::FakeHttpClient::create(|_| async { unreachable!() });
         let node_runtime = NodeRuntime::unavailable();
@@ -468,7 +469,7 @@ impl Copilot {
         env: Option<HashMap<String, String>>,
         this: WeakEntity<Self>,
         awaiting_sign_in_after_start: bool,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) {
         let start_language_server = async {
             let server_path = get_copilot_lsp(http).await?;
@@ -495,7 +496,7 @@ impl Copilot {
                 root_path,
                 None,
                 Default::default(),
-                cx.clone(),
+                cx,
             )?;
 
             server
@@ -535,7 +536,7 @@ impl Copilot {
         };
 
         let server = start_language_server.await;
-        this.update(&mut cx, |this, cx| {
+        this.update(cx, |this, cx| {
             cx.notify();
             match server {
                 Ok((server, status)) => {
@@ -569,7 +570,7 @@ impl Copilot {
                 SignInStatus::SignedOut { .. } | SignInStatus::Unauthorized { .. } => {
                     let lsp = server.lsp.clone();
                     let task = cx
-                        .spawn(|this, mut cx| async move {
+                        .spawn(async move |this, cx| {
                             let sign_in = async {
                                 let sign_in = lsp
                                     .request::<request::SignInInitiate>(
@@ -581,7 +582,7 @@ impl Copilot {
                                         Ok(request::SignInStatus::Ok { user: Some(user) })
                                     }
                                     request::SignInInitiateResult::PromptUserDeviceFlow(flow) => {
-                                        this.update(&mut cx, |this, cx| {
+                                        this.update(cx, |this, cx| {
                                             if let CopilotServer::Running(RunningCopilotServer {
                                                 sign_in_status: status,
                                                 ..
@@ -610,7 +611,7 @@ impl Copilot {
                             };
 
                             let sign_in = sign_in.await;
-                            this.update(&mut cx, |this, cx| match sign_in {
+                            this.update(cx, |this, cx| match sign_in {
                                 Ok(status) => {
                                     this.update_sign_in_status(status, cx);
                                     Ok(())
@@ -670,7 +671,7 @@ impl Copilot {
                 let http = self.http.clone();
                 let node_runtime = self.node_runtime.clone();
                 let server_id = self.server_id;
-                move |this, cx| async move {
+                async move |this, cx| {
                     clear_copilot_dir().await;
                     Self::start_language_server(server_id, http, node_runtime, env, this, false, cx)
                         .await

crates/copilot/src/copilot_chat.rs 🔗

@@ -241,7 +241,7 @@ impl CopilotChat {
         let config_paths: HashSet<PathBuf> = copilot_chat_config_paths().into_iter().collect();
         let dir_path = copilot_chat_config_dir();
 
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             let mut parent_watch_rx = watch_config_dir(
                 cx.background_executor(),
                 fs.clone(),

crates/copilot/src/copilot_completion_provider.rs 🔗

@@ -83,7 +83,7 @@ impl EditPredictionProvider for CopilotCompletionProvider {
         cx: &mut Context<Self>,
     ) {
         let copilot = self.copilot.clone();
-        self.pending_refresh = Some(cx.spawn(|this, mut cx| async move {
+        self.pending_refresh = Some(cx.spawn(async move |this, cx| {
             if debounce {
                 cx.background_executor()
                     .timer(COPILOT_DEBOUNCE_TIMEOUT)
@@ -91,12 +91,12 @@ impl EditPredictionProvider for CopilotCompletionProvider {
             }
 
             let completions = copilot
-                .update(&mut cx, |copilot, cx| {
+                .update(cx, |copilot, cx| {
                     copilot.completions(&buffer, cursor_position, cx)
                 })?
                 .await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 if !completions.is_empty() {
                     this.cycled = false;
                     this.pending_refresh = None;
@@ -153,14 +153,14 @@ impl EditPredictionProvider for CopilotCompletionProvider {
             cx.notify();
         } else {
             let copilot = self.copilot.clone();
-            self.pending_cycling_refresh = Some(cx.spawn(|this, mut cx| async move {
+            self.pending_cycling_refresh = Some(cx.spawn(async move |this, cx| {
                 let completions = copilot
-                    .update(&mut cx, |copilot, cx| {
+                    .update(cx, |copilot, cx| {
                         copilot.completions_cycling(&buffer, cursor_position, cx)
                     })?
                     .await?;
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.cycled = true;
                     this.file_extension = buffer.read(cx).file().and_then(|file| {
                         Some(

crates/copilot/src/sign_in.rs 🔗

@@ -37,11 +37,11 @@ pub fn initiate_sign_in(window: &mut Window, cx: &mut App) {
             });
 
             let workspace = workspace.downgrade();
-            cx.spawn(|mut cx| async move {
+            cx.spawn(async move |cx| {
                 task.await;
                 if let Some(copilot) = cx.update(|cx| Copilot::global(cx)).ok().flatten() {
                     workspace
-                        .update(&mut cx, |workspace, cx| match copilot.read(cx).status() {
+                        .update(cx, |workspace, cx| match copilot.read(cx).status() {
                             Status::Authorized => workspace.show_toast(
                                 Toast::new(
                                     NotificationId::unique::<CopilotStartingToast>(),

crates/dap/src/transport.rs 🔗

@@ -583,7 +583,7 @@ impl TcpTransport {
             _ = cx.background_executor().timer(Duration::from_millis(timeout)).fuse() => {
                 return Err(anyhow!(format!("Connection to TCP DAP timeout {}:{}", host, port)))
             },
-            result = cx.spawn(|cx| async move {
+            result = cx.spawn(async move |cx| {
                 loop {
                     match TcpStream::connect(address).await {
                         Ok(stream) => return stream.split(),

crates/debugger_tools/src/dap_log.rs 🔗

@@ -103,10 +103,10 @@ impl DebugAdapterState {
 impl LogStore {
     fn new(cx: &Context<Self>) -> Self {
         let (rpc_tx, mut rpc_rx) = unbounded::<(SessionId, IoKind, String)>();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             while let Some((client_id, io_kind, message)) = rpc_rx.next().await {
                 if let Some(this) = this.upgrade() {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.on_rpc_log(client_id, io_kind, &message, cx);
                     })?;
                 }
@@ -118,10 +118,10 @@ impl LogStore {
         .detach_and_log_err(cx);
 
         let (adapter_log_tx, mut adapter_log_rx) = unbounded::<(SessionId, IoKind, String)>();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             while let Some((client_id, io_kind, message)) = adapter_log_rx.next().await {
                 if let Some(this) = this.upgrade() {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.on_adapter_log(client_id, io_kind, &message, cx);
                     })?;
                 }
@@ -604,9 +604,9 @@ impl DapLogView {
                 .update(cx, |_, cx| {
                     cx.spawn({
                         let buffer = cx.entity();
-                        |_, mut cx| async move {
+                        async move |_, cx| {
                             let language = language.await.ok();
-                            buffer.update(&mut cx, |buffer, cx| {
+                            buffer.update(cx, |buffer, cx| {
                                 buffer.set_language(language, cx);
                             })
                         }

crates/debugger_ui/src/attach_modal.rs 🔗

@@ -114,9 +114,9 @@ impl PickerDelegate for AttachModalDelegate {
         _window: &mut Window,
         cx: &mut Context<Picker<Self>>,
     ) -> gpui::Task<()> {
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let Some(processes) = this
-                .update(&mut cx, |this, _| {
+                .update(cx, |this, _| {
                     if let Some(processes) = this.delegate.candidates.clone() {
                         processes
                     } else {
@@ -172,7 +172,7 @@ impl PickerDelegate for AttachModalDelegate {
             )
             .await;
 
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 let delegate = &mut this.delegate;
 
                 delegate.matches = matches;

crates/debugger_ui/src/debugger_panel.rs 🔗

@@ -150,8 +150,8 @@ impl DebugPanel {
         workspace: WeakEntity<Workspace>,
         cx: AsyncWindowContext,
     ) -> Task<Result<Entity<Self>>> {
-        cx.spawn(|mut cx| async move {
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+        cx.spawn(async move |cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 let debug_panel = DebugPanel::new(workspace, window, cx);
 
                 cx.observe(&debug_panel, |_, debug_panel, cx| {
@@ -349,11 +349,11 @@ impl DebugPanel {
                     cx,
                 );
 
-                cx.spawn(|_, mut cx| async move {
+                cx.spawn(async move |_, cx| {
                     let pid_task = async move {
                         let terminal = terminal_task.await?;
 
-                        terminal.read_with(&mut cx, |terminal, _| terminal.pty_info.pid())
+                        terminal.read_with(cx, |terminal, _| terminal.pty_info.pid())
                     };
 
                     pid_task.await

crates/debugger_ui/src/session/running/console.rs 🔗

@@ -213,8 +213,8 @@ impl Render for Console {
     fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
         let session = self.session.clone();
         let token = self.last_token;
-        self.update_output_task = cx.spawn_in(window, move |this, mut cx| async move {
-            _ = session.update_in(&mut cx, move |session, window, cx| {
+        self.update_output_task = cx.spawn_in(window, async move |this, cx| {
+            _ = session.update_in(cx, move |session, window, cx| {
                 let (output, last_processed_token) = session.output(token);
 
                 _ = this.update(cx, |this, cx| {
@@ -342,7 +342,7 @@ impl ConsoleQueryBarCompletionProvider {
 
         let query = buffer.read(cx).text();
 
-        cx.spawn(|_, cx| async move {
+        cx.spawn(async move |_, cx| {
             let matches = fuzzy::match_strings(
                 &string_matches,
                 &query,

crates/debugger_ui/src/session/running/module_list.rs 🔗

@@ -60,9 +60,9 @@ impl ModuleList {
     }
 
     fn open_module(&mut self, path: Arc<Path>, window: &mut Window, cx: &mut Context<Self>) {
-        cx.spawn_in(window, move |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let (worktree, relative_path) = this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     this.workspace.update(cx, |workspace, cx| {
                         workspace.project().update(cx, |this, cx| {
                             this.find_or_create_worktree(&path, false, cx)
@@ -72,7 +72,7 @@ impl ModuleList {
                 .await?;
 
             let buffer = this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     this.workspace.update(cx, |this, cx| {
                         this.project().update(cx, |this, cx| {
                             let worktree_id = worktree.read(cx).id();
@@ -88,7 +88,7 @@ impl ModuleList {
                 })??
                 .await?;
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.workspace.update(cx, |workspace, cx| {
                     let project_path = buffer.read(cx).project_path(cx).ok_or_else(|| {
                         anyhow!("Could not select a stack frame for unnamed buffer")

crates/debugger_ui/src/session/running/stack_frame_list.rs 🔗

@@ -235,9 +235,9 @@ impl StackFrameList {
             return Task::ready(Err(anyhow!("Project path not found")));
         };
 
-        cx.spawn_in(window, move |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let (worktree, relative_path) = this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     this.workspace.update(cx, |workspace, cx| {
                         workspace.project().update(cx, |this, cx| {
                             this.find_or_create_worktree(&abs_path, false, cx)
@@ -246,7 +246,7 @@ impl StackFrameList {
                 })??
                 .await?;
             let buffer = this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     this.workspace.update(cx, |this, cx| {
                         this.project().update(cx, |this, cx| {
                             let worktree_id = worktree.read(cx).id();
@@ -261,10 +261,10 @@ impl StackFrameList {
                     })
                 })??
                 .await?;
-            let position = buffer.update(&mut cx, |this, _| {
+            let position = buffer.update(cx, |this, _| {
                 this.snapshot().anchor_after(PointUtf16::new(row, 0))
             })?;
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.workspace.update(cx, |workspace, cx| {
                     let project_path = buffer.read(cx).project_path(cx).ok_or_else(|| {
                         anyhow!("Could not select a stack frame for unnamed buffer")
@@ -282,7 +282,7 @@ impl StackFrameList {
             })???
             .await?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.workspace.update(cx, |workspace, cx| {
                     let breakpoint_store = workspace.project().read(cx).breakpoint_store();
 

crates/debugger_ui/src/session/starting.rs 🔗

@@ -29,10 +29,10 @@ impl StartingState {
         task: Task<Result<Entity<Session>>>,
         cx: &mut Context<Self>,
     ) -> Self {
-        let _notify_parent = cx.spawn(move |this, mut cx| async move {
+        let _notify_parent = cx.spawn(async move |this, cx| {
             let entity = task.await;
 
-            this.update(&mut cx, |_, cx| {
+            this.update(cx, |_, cx| {
                 if let Ok(entity) = entity {
                     cx.emit(StartingEvent::Finished(entity))
                 } else {

crates/debugger_ui/src/tests.rs 🔗

@@ -40,13 +40,21 @@ pub async fn init_test_workspace(
         cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
 
     let debugger_panel = workspace_handle
-        .update(cx, |_, window, cx| cx.spawn_in(window, DebugPanel::load))
+        .update(cx, |_, window, cx| {
+            cx.spawn_in(window, async move |this, cx| {
+                DebugPanel::load(this, cx.clone()).await
+            })
+        })
         .unwrap()
         .await
         .expect("Failed to load debug panel");
 
     let terminal_panel = workspace_handle
-        .update(cx, |_, window, cx| cx.spawn_in(window, TerminalPanel::load))
+        .update(cx, |_, window, cx| {
+            cx.spawn_in(window, async |this, cx| {
+                TerminalPanel::load(this, cx.clone()).await
+            })
+        })
         .unwrap()
         .await
         .expect("Failed to load terminal panel");

crates/diagnostics/src/diagnostics.rs 🔗

@@ -251,12 +251,12 @@ impl ProjectDiagnosticsEditor {
             return;
         }
         let project_handle = self.project.clone();
-        self.update_excerpts_task = Some(cx.spawn_in(window, |this, mut cx| async move {
+        self.update_excerpts_task = Some(cx.spawn_in(window, async move |this, cx| {
             cx.background_executor()
                 .timer(DIAGNOSTICS_UPDATE_DEBOUNCE)
                 .await;
             loop {
-                let Some((path, language_server_id)) = this.update(&mut cx, |this, _| {
+                let Some((path, language_server_id)) = this.update(cx, |this, _| {
                     let Some((path, language_server_id)) = this.paths_to_update.pop_first() else {
                         this.update_excerpts_task.take();
                         return None;
@@ -268,11 +268,11 @@ impl ProjectDiagnosticsEditor {
                 };
 
                 if let Some(buffer) = project_handle
-                    .update(&mut cx, |project, cx| project.open_buffer(path.clone(), cx))?
+                    .update(cx, |project, cx| project.open_buffer(path.clone(), cx))?
                     .await
                     .log_err()
                 {
-                    this.update_in(&mut cx, |this, window, cx| {
+                    this.update_in(cx, |this, window, cx| {
                         this.update_excerpts(path, language_server_id, buffer, window, cx)
                     })?
                     .await?;
@@ -419,9 +419,9 @@ impl ProjectDiagnosticsEditor {
         let excerpts = self.excerpts.clone().downgrade();
         let context = self.context;
         let editor = self.editor.clone().downgrade();
-        cx.spawn_in(window, move |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let mut old_groups = this
-                .update(&mut cx, |this, _| {
+                .update(cx, |this, _| {
                     mem::take(&mut this.path_states[path_ix].diagnostic_groups)
                 })?
                 .into_iter()
@@ -491,7 +491,7 @@ impl ProjectDiagnosticsEditor {
                                     entry.range.clone(),
                                     context,
                                     snapshot.clone(),
-                                    (*cx).clone(),
+                                    (**cx).clone(),
                                 )
                                 .await,
                             )
@@ -507,7 +507,7 @@ impl ProjectDiagnosticsEditor {
                                 }
                             }
 
-                            let excerpt_id = excerpts.update(&mut cx, |excerpts, cx| {
+                            let excerpt_id = excerpts.update(cx, |excerpts, cx| {
                                 excerpts
                                     .insert_excerpts_after(
                                         prev_excerpt_id,
@@ -575,14 +575,14 @@ impl ProjectDiagnosticsEditor {
                         }
                     }
 
-                    this.update(&mut cx, |this, _| {
+                    this.update(cx, |this, _| {
                         new_group_ixs.push(this.path_states[path_ix].diagnostic_groups.len());
                         this.path_states[path_ix]
                             .diagnostic_groups
                             .push(group_state);
                     })?;
                 } else if let Some((_, group_state)) = to_remove {
-                    excerpts.update(&mut cx, |excerpts, cx| {
+                    excerpts.update(cx, |excerpts, cx| {
                         excerpts.remove_excerpts(group_state.excerpts.iter().copied(), cx)
                     })?;
                     blocks_to_remove.extend(group_state.blocks.iter().copied());
@@ -590,7 +590,7 @@ impl ProjectDiagnosticsEditor {
                     prev_excerpt_id = *group_state.excerpts.last().unwrap();
                     first_excerpt_id.get_or_insert(prev_excerpt_id);
 
-                    this.update(&mut cx, |this, _| {
+                    this.update(cx, |this, _| {
                         this.path_states[path_ix]
                             .diagnostic_groups
                             .push(group_state)
@@ -598,9 +598,8 @@ impl ProjectDiagnosticsEditor {
                 }
             }
 
-            let excerpts_snapshot =
-                excerpts.update(&mut cx, |excerpts, cx| excerpts.snapshot(cx))?;
-            editor.update(&mut cx, |editor, cx| {
+            let excerpts_snapshot = excerpts.update(cx, |excerpts, cx| excerpts.snapshot(cx))?;
+            editor.update(cx, |editor, cx| {
                 editor.remove_blocks(blocks_to_remove, None, cx);
                 let block_ids = editor.insert_blocks(
                     blocks_to_add.into_iter().flat_map(|block| {
@@ -644,7 +643,7 @@ impl ProjectDiagnosticsEditor {
                 Result::<(), anyhow::Error>::Ok(())
             })??;
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 if this.path_states[path_ix].diagnostic_groups.is_empty() {
                     this.path_states.remove(path_ix);
                 }
@@ -709,7 +708,7 @@ impl ProjectDiagnosticsEditor {
                 });
             })?;
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 if this.path_states.is_empty() {
                     if this.editor.focus_handle(cx).is_focused(window) {
                         window.focus(&this.focus_handle);
@@ -1053,7 +1052,7 @@ fn context_range_for_entry(
     snapshot: BufferSnapshot,
     cx: AsyncApp,
 ) -> Task<Range<Point>> {
-    cx.spawn(move |cx| async move {
+    cx.spawn(async move |cx| {
         if let Some(rows) = heuristic_syntactic_expand(
             range.clone(),
             DIAGNOSTIC_EXPANSION_ROW_LIMIT,
@@ -1083,7 +1082,7 @@ async fn heuristic_syntactic_expand(
     input_range: Range<Point>,
     max_row_count: u32,
     snapshot: BufferSnapshot,
-    cx: AsyncApp,
+    cx: &mut AsyncApp,
 ) -> Option<RangeInclusive<BufferRow>> {
     let input_row_count = input_range.end.row - input_range.start.row;
     if input_row_count > max_row_count {

crates/diagnostics/src/items.rs 🔗

@@ -163,12 +163,12 @@ impl DiagnosticIndicator {
             .map(|entry| entry.diagnostic);
         if new_diagnostic != self.current_diagnostic {
             self.diagnostics_update =
-                cx.spawn_in(window, |diagnostics_indicator, mut cx| async move {
+                cx.spawn_in(window, async move |diagnostics_indicator, cx| {
                     cx.background_executor()
                         .timer(Duration::from_millis(50))
                         .await;
                     diagnostics_indicator
-                        .update(&mut cx, |diagnostics_indicator, cx| {
+                        .update(cx, |diagnostics_indicator, cx| {
                             diagnostics_indicator.current_diagnostic = new_diagnostic;
                             cx.notify();
                         })
@@ -40,9 +40,9 @@ impl BlinkManager {
 
         let epoch = self.next_blink_epoch();
         let interval = self.blink_interval;
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             Timer::after(interval).await;
-            this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
+            this.update(cx, |this, cx| this.resume_cursor_blinking(epoch, cx))
         })
         .detach();
     }
@@ -62,10 +62,10 @@ impl BlinkManager {
 
                 let epoch = self.next_blink_epoch();
                 let interval = self.blink_interval;
-                cx.spawn(|this, mut cx| async move {
+                cx.spawn(async move |this, cx| {
                     Timer::after(interval).await;
                     if let Some(this) = this.upgrade() {
-                        this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx))
+                        this.update(cx, |this, cx| this.blink_cursors(epoch, cx))
                             .ok();
                     }
                 })

crates/editor/src/clangd_ext.rs 🔗

@@ -51,7 +51,7 @@ pub fn switch_source_header(
             cx,
         )
     });
-    cx.spawn_in(window, |_editor, mut cx| async move {
+    cx.spawn_in(window, async move |_editor, cx| {
         let switch_source_header = switch_source_header_task
             .await
             .with_context(|| format!("Switch source/header LSP request for path \"{source_file}\" failed"))?;
@@ -72,7 +72,7 @@ pub fn switch_source_header(
         })?;
 
         workspace
-            .update_in(&mut cx, |workspace, window, cx| {
+            .update_in(cx, |workspace, window, cx| {
                 workspace.open_abs_path(path, OpenOptions { visible: Some(OpenVisible::None), ..Default::default() }, window, cx)
             })
             .with_context(|| {

crates/editor/src/code_context_menus.rs 🔗

@@ -416,9 +416,9 @@ impl CompletionsMenu {
             cx,
         );
 
-        cx.spawn(move |editor, mut cx| async move {
+        cx.spawn(async move |editor, cx| {
             if let Some(true) = resolve_task.await.log_err() {
-                editor.update(&mut cx, |_, cx| cx.notify()).ok();
+                editor.update(cx, |_, cx| cx.notify()).ok();
             }
         })
         .detach();

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

@@ -198,9 +198,9 @@ impl WrapMap {
                     self.edits_since_sync = self.edits_since_sync.compose(&edits);
                 }
                 Err(wrap_task) => {
-                    self.background_task = Some(cx.spawn(|this, mut cx| async move {
+                    self.background_task = Some(cx.spawn(async move |this, cx| {
                         let (snapshot, edits) = wrap_task.await;
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             this.snapshot = snapshot;
                             this.edits_since_sync = this
                                 .edits_since_sync
@@ -276,9 +276,9 @@ impl WrapMap {
                         self.edits_since_sync = self.edits_since_sync.compose(&output_edits);
                     }
                     Err(update_task) => {
-                        self.background_task = Some(cx.spawn(|this, mut cx| async move {
+                        self.background_task = Some(cx.spawn(async move |this, cx| {
                             let (snapshot, edits) = update_task.await;
-                            this.update(&mut cx, |this, cx| {
+                            this.update(cx, |this, cx| {
                                 this.snapshot = snapshot;
                                 this.edits_since_sync = this
                                     .edits_since_sync

crates/editor/src/editor.rs 🔗

@@ -185,7 +185,7 @@ use ui::{
     h_flex, prelude::*, ButtonSize, ButtonStyle, Disclosure, IconButton, IconName, IconSize, Key,
     Tooltip,
 };
-use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
+use util::{maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
 use workspace::{
     item::{ItemHandle, PreviewTabsSettings},
     ItemId, RestoreOnStartupBehavior,
@@ -1715,9 +1715,9 @@ impl Editor {
         let project = workspace.project().clone();
         let create = project.update(cx, |project, cx| project.create_buffer(cx));
 
-        cx.spawn_in(window, |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             let buffer = create.await?;
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 let editor =
                     cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
                 workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
@@ -1753,9 +1753,9 @@ impl Editor {
         let project = workspace.project().clone();
         let create = project.update(cx, |project, cx| project.create_buffer(cx));
 
-        cx.spawn_in(window, |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             let buffer = create.await?;
-            workspace.update_in(&mut cx, move |workspace, window, cx| {
+            workspace.update_in(cx, move |workspace, window, cx| {
                 workspace.split_item(
                     direction,
                     Box::new(
@@ -2184,12 +2184,12 @@ impl Editor {
                     drop(context_menu);
 
                     let query = Self::completion_query(buffer, cursor_position);
-                    cx.spawn(move |this, mut cx| async move {
+                    cx.spawn(async move |this, cx| {
                         completion_menu
                             .filter(query.as_deref(), cx.background_executor().clone())
                             .await;
 
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             let mut context_menu = this.context_menu.borrow_mut();
                             let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
                             else {
@@ -4050,16 +4050,16 @@ impl Editor {
                 cx,
             )
         });
-        Some(cx.spawn_in(window, |editor, mut cx| async move {
+        Some(cx.spawn_in(window, async move |editor, cx| {
             if let Some(transaction) = on_type_formatting.await? {
                 if push_to_client_history {
                     buffer
-                        .update(&mut cx, |buffer, _| {
+                        .update(cx, |buffer, _| {
                             buffer.push_transaction(transaction, Instant::now());
                         })
                         .ok();
                 }
-                editor.update(&mut cx, |editor, cx| {
+                editor.update(cx, |editor, cx| {
                     editor.refresh_document_highlights(cx);
                 })?;
             }
@@ -4215,9 +4215,9 @@ impl Editor {
             .map_or(true, |provider| provider.sort_completions());
 
         let id = post_inc(&mut self.next_completion_id);
-        let task = cx.spawn_in(window, |editor, mut cx| {
+        let task = cx.spawn_in(window, async move |editor, cx| {
             async move {
-                editor.update(&mut cx, |this, _| {
+                editor.update(cx, |this, _| {
                     this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
                 })?;
 
@@ -4267,7 +4267,7 @@ impl Editor {
                     menu.visible().then_some(menu)
                 };
 
-                editor.update_in(&mut cx, |editor, window, cx| {
+                editor.update_in(cx, |editor, window, cx| {
                     match editor.context_menu.borrow().as_ref() {
                         None => {}
                         Some(CodeContextMenu::Completions(prev_menu)) => {
@@ -4308,6 +4308,7 @@ impl Editor {
                 anyhow::Ok(())
             }
             .log_err()
+            .await
         });
 
         self.completion_tasks.push((id, task));
@@ -4550,13 +4551,13 @@ impl Editor {
         let deployed_from_indicator = action.deployed_from_indicator;
         let mut task = self.code_actions_task.take();
         let action = action.clone();
-        cx.spawn_in(window, |editor, mut cx| async move {
+        cx.spawn_in(window, async move |editor, cx| {
             while let Some(prev_task) = task {
                 prev_task.await.log_err();
-                task = editor.update(&mut cx, |this, _| this.code_actions_task.take())?;
+                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
             }
 
-            let spawned_test_task = editor.update_in(&mut cx, |editor, window, cx| {
+            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
                 if editor.focus_handle.is_focused(window) {
                     let multibuffer_point = action
                         .deployed_from_indicator
@@ -4605,7 +4606,7 @@ impl Editor {
                                 Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
                             });
 
-                    Some(cx.spawn_in(window, |editor, mut cx| async move {
+                    Some(cx.spawn_in(window, async move |editor, cx| {
                         let task_context = match task_context {
                             Some(task_context) => task_context.await,
                             None => None,
@@ -4626,7 +4627,7 @@ impl Editor {
                             && code_actions
                                 .as_ref()
                                 .map_or(true, |actions| actions.is_empty());
-                        if let Ok(task) = editor.update_in(&mut cx, |editor, window, cx| {
+                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
                             *editor.context_menu.borrow_mut() =
                                 Some(CodeContextMenu::CodeActions(CodeActionsMenu {
                                     buffer,
@@ -4709,7 +4710,7 @@ impl Editor {
                 let apply_code_action =
                     provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
                 let workspace = workspace.downgrade();
-                Some(cx.spawn_in(window, |editor, cx| async move {
+                Some(cx.spawn_in(window, async move |editor, cx| {
                     let project_transaction = apply_code_action.await?;
                     Self::open_project_transaction(
                         &editor,
@@ -4729,7 +4730,7 @@ impl Editor {
         workspace: WeakEntity<Workspace>,
         transaction: ProjectTransaction,
         title: String,
-        mut cx: AsyncWindowContext,
+        cx: &mut AsyncWindowContext,
     ) -> Result<()> {
         let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
         cx.update(|_, cx| {
@@ -4743,7 +4744,7 @@ impl Editor {
 
         if let Some((buffer, transaction)) = entries.first() {
             if entries.len() == 1 {
-                let excerpt = this.update(&mut cx, |editor, cx| {
+                let excerpt = this.update(cx, |editor, cx| {
                     editor
                         .buffer()
                         .read(cx)
@@ -4751,7 +4752,7 @@ impl Editor {
                 })?;
                 if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
                     if excerpted_buffer == *buffer {
-                        let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
+                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
                             let excerpt_range = excerpt_range.to_offset(buffer);
                             buffer
                                 .edited_ranges_for_transaction::<usize>(transaction)
@@ -4791,7 +4792,7 @@ impl Editor {
             multibuffer
         })?;
 
-        workspace.update_in(&mut cx, |workspace, window, cx| {
+        workspace.update_in(cx, |workspace, window, cx| {
             let project = workspace.project().clone();
             let editor =
                 cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
@@ -4854,12 +4855,12 @@ impl Editor {
             return None;
         }
 
-        self.code_actions_task = Some(cx.spawn_in(window, |this, mut cx| async move {
+        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
             cx.background_executor()
                 .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
                 .await;
 
-            let (providers, tasks) = this.update_in(&mut cx, |this, window, cx| {
+            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
                 let providers = this.code_action_providers.clone();
                 let tasks = this
                     .code_action_providers
@@ -4884,7 +4885,7 @@ impl Editor {
                 }
             }
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.available_code_actions = if actions.is_empty() {
                     None
                 } else {
@@ -4907,10 +4908,10 @@ impl Editor {
             self.show_git_blame_inline = false;
 
             self.show_git_blame_inline_delay_task =
-                Some(cx.spawn_in(window, |this, mut cx| async move {
+                Some(cx.spawn_in(window, async move |this, cx| {
                     cx.background_executor().timer(delay).await;
 
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.show_git_blame_inline = true;
                         cx.notify();
                     })
@@ -4935,7 +4936,7 @@ impl Editor {
             return None;
         }
         let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
-        self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move {
+        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
             cx.background_executor()
                 .timer(Duration::from_millis(debounce))
                 .await;
@@ -4953,7 +4954,7 @@ impl Editor {
             };
 
             if let Some(highlights) = highlights {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     if this.pending_rename.is_some() {
                         return;
                     }
@@ -5046,12 +5047,12 @@ impl Editor {
             return;
         }
         let debounce = EditorSettings::get_global(cx).selection_highlight_debounce;
-        self.selection_highlight_task = Some(cx.spawn_in(window, |editor, mut cx| async move {
+        self.selection_highlight_task = Some(cx.spawn_in(window, async move |editor, cx| {
             cx.background_executor()
                 .timer(Duration::from_millis(debounce))
                 .await;
             let Some(Some(matches_task)) = editor
-                .update_in(&mut cx, |editor, _, cx| {
+                .update_in(cx, |editor, _, cx| {
                     if editor.selections.count() != 1 || editor.selections.line_mode {
                         editor.clear_background_highlights::<SelectedTextHighlight>(cx);
                         return None;
@@ -5116,7 +5117,7 @@ impl Editor {
             };
             let matches = matches_task.await;
             editor
-                .update_in(&mut cx, |editor, _, cx| {
+                .update_in(cx, |editor, _, cx| {
                     editor.clear_background_highlights::<SelectedTextHighlight>(cx);
                     if !matches.is_empty() {
                         editor.highlight_background::<SelectedTextHighlight>(
@@ -5342,9 +5343,9 @@ impl Editor {
     fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         self.show_cursor_names = true;
         cx.notify();
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.show_cursor_names = false;
                 cx.notify()
             })
@@ -6230,7 +6231,7 @@ impl Editor {
 
         let reveal_strategy = action.reveal;
         let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             let context = task_context.await?;
             let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 
@@ -6238,7 +6239,7 @@ impl Editor {
             resolved.reveal = reveal_strategy;
 
             workspace
-                .update(&mut cx, |workspace, cx| {
+                .update(cx, |workspace, cx| {
                     workspace::tasks::schedule_resolved_task(
                         workspace,
                         task_source_kind,
@@ -11806,19 +11807,19 @@ impl Editor {
             return Task::ready(());
         }
         let project = self.project.as_ref().map(Entity::downgrade);
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             cx.background_executor().timer(UPDATE_DEBOUNCE).await;
             let Some(project) = project.and_then(|p| p.upgrade()) else {
                 return;
             };
-            let Ok(display_snapshot) = this.update(&mut cx, |this, cx| {
+            let Ok(display_snapshot) = this.update(cx, |this, cx| {
                 this.display_map.update(cx, |map, cx| map.snapshot(cx))
             }) else {
                 return;
             };
 
             let hide_runnables = project
-                .update(&mut cx, |project, cx| {
+                .update(cx, |project, cx| {
                     // Do not display any test indicators in non-dev server remote projects.
                     project.is_via_collab() && project.ssh_connection_string(cx).is_none()
                 })
@@ -11836,7 +11837,7 @@ impl Editor {
                     .await;
 
             let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 this.clear_tasks();
                 for (key, value) in rows {
                     this.insert_tasks(key, value);
@@ -12425,11 +12426,11 @@ impl Editor {
     ) -> Task<Result<Navigated>> {
         let definition =
             self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
-        cx.spawn_in(window, |editor, mut cx| async move {
+        cx.spawn_in(window, async move |editor, cx| {
             if definition.await? == Navigated::Yes {
                 return Ok(Navigated::Yes);
             }
-            match editor.update_in(&mut cx, |editor, window, cx| {
+            match editor.update_in(cx, |editor, window, cx| {
                 editor.find_all_references(&FindAllReferences, window, cx)
             })? {
                 Some(references) => references.await,
@@ -12523,10 +12524,10 @@ impl Editor {
             return Task::ready(Ok(Navigated::No));
         };
 
-        cx.spawn_in(window, |editor, mut cx| async move {
+        cx.spawn_in(window, async move |editor, cx| {
             let definitions = definitions.await?;
             let navigated = editor
-                .update_in(&mut cx, |editor, window, cx| {
+                .update_in(cx, |editor, window, cx| {
                     editor.navigate_to_hover_links(
                         Some(kind),
                         definitions
@@ -12566,7 +12567,7 @@ impl Editor {
             None
         };
 
-        let url_finder = cx.spawn_in(window, |editor, mut cx| async move {
+        let url_finder = cx.spawn_in(window, async move |editor, cx| {
             let url = if let Some(end_pos) = end_position {
                 find_url_from_range(&buffer, start_position..end_pos, cx.clone())
             } else {
@@ -12574,7 +12575,7 @@ impl Editor {
             };
 
             if let Some(url) = url {
-                editor.update(&mut cx, |_, cx| {
+                editor.update(cx, |_, cx| {
                     cx.open_url(&url);
                 })
             } else {
@@ -12605,12 +12606,12 @@ impl Editor {
 
         let project = self.project.clone();
 
-        cx.spawn_in(window, |_, mut cx| async move {
-            let result = find_file(&buffer, project, buffer_position, &mut cx).await;
+        cx.spawn_in(window, async move |_, cx| {
+            let result = find_file(&buffer, project, buffer_position, cx).await;
 
             if let Some((_, path)) = result {
                 workspace
-                    .update_in(&mut cx, |workspace, window, cx| {
+                    .update_in(cx, |workspace, window, cx| {
                         workspace.open_resolved_path(path, window, cx)
                     })?
                     .await?;
@@ -12655,9 +12656,9 @@ impl Editor {
                 }
                 HoverLink::File(path) => {
                     if let Some(workspace) = self.workspace() {
-                        cx.spawn_in(window, |_, mut cx| async move {
+                        cx.spawn_in(window, async move |_, cx| {
                             workspace
-                                .update_in(&mut cx, |workspace, window, cx| {
+                                .update_in(cx, |workspace, window, cx| {
                                     workspace.open_resolved_path(path, window, cx)
                                 })?
                                 .await
@@ -12668,14 +12669,14 @@ impl Editor {
                     }
                 }
             };
-            cx.spawn_in(window, |editor, mut cx| async move {
+            cx.spawn_in(window, async move |editor, cx| {
                 let target = match target_task.await.context("target resolution task")? {
                     TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
                     TargetTaskResult::Location(None) => return Ok(Navigated::No),
                     TargetTaskResult::Location(Some(target)) => target,
                 };
 
-                editor.update_in(&mut cx, |editor, window, cx| {
+                editor.update_in(cx, |editor, window, cx| {
                     let Some(workspace) = editor.workspace() else {
                         return Navigated::No;
                     };
@@ -12721,9 +12722,9 @@ impl Editor {
                 })
             })
         } else if !definitions.is_empty() {
-            cx.spawn_in(window, |editor, mut cx| async move {
+            cx.spawn_in(window, async move |editor, cx| {
                 let (title, location_tasks, workspace) = editor
-                    .update_in(&mut cx, |editor, window, cx| {
+                    .update_in(cx, |editor, window, cx| {
                         let tab_kind = match kind {
                             Some(GotoDefinitionKind::Implementation) => "Implementations",
                             _ => "Definitions",
@@ -12771,7 +12772,7 @@ impl Editor {
                     return Ok(Navigated::No);
                 };
                 let opened = workspace
-                    .update_in(&mut cx, |workspace, window, cx| {
+                    .update_in(cx, |workspace, window, cx| {
                         Self::open_locations_in_multibuffer(
                             workspace,
                             locations,
@@ -12802,8 +12803,8 @@ impl Editor {
             return Task::ready(Ok(None));
         };
 
-        cx.spawn_in(window, move |editor, mut cx| async move {
-            let location_task = editor.update(&mut cx, |_, cx| {
+        cx.spawn_in(window, async move |editor, cx| {
+            let location_task = editor.update(cx, |_, cx| {
                 project.update(cx, |project, cx| {
                     let language_server_name = project
                         .language_server_statuses(cx)
@@ -12822,7 +12823,7 @@ impl Editor {
             let location = match location_task {
                 Some(task) => Some({
                     let target_buffer_handle = task.await.context("open local buffer")?;
-                    let range = target_buffer_handle.update(&mut cx, |target_buffer, _| {
+                    let range = target_buffer_handle.update(cx, |target_buffer, _| {
                         let target_start = target_buffer
                             .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
                         let target_end = target_buffer
@@ -12880,21 +12881,13 @@ impl Editor {
         let workspace = self.workspace()?;
         let project = workspace.read(cx).project().clone();
         let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
-        Some(cx.spawn_in(window, |editor, mut cx| async move {
-            let _cleanup = defer({
-                let mut cx = cx.clone();
-                move || {
-                    let _ = editor.update(&mut cx, |editor, _| {
-                        if let Ok(i) =
-                            editor
-                                .find_all_references_task_sources
-                                .binary_search_by(|anchor| {
-                                    anchor.cmp(&head_anchor, &multi_buffer_snapshot)
-                                })
-                        {
-                            editor.find_all_references_task_sources.remove(i);
-                        }
-                    });
+        Some(cx.spawn_in(window, async move |editor, cx| {
+            let _cleanup = cx.on_drop(&editor, move |editor, _| {
+                if let Ok(i) = editor
+                    .find_all_references_task_sources
+                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
+                {
+                    editor.find_all_references_task_sources.remove(i);
                 }
             });
 
@@ -12903,7 +12896,7 @@ impl Editor {
                 return anyhow::Ok(Navigated::No);
             }
 
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 let title = locations
                     .first()
                     .as_ref()
@@ -13067,11 +13060,11 @@ impl Editor {
             .unwrap_or_else(|| Task::ready(Ok(None)));
         drop(snapshot);
 
-        Some(cx.spawn_in(window, |this, mut cx| async move {
+        Some(cx.spawn_in(window, async move |this, cx| {
             let rename_range = if let Some(range) = prepare_rename.await? {
                 Some(range)
             } else {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     let buffer = this.buffer.read(cx).snapshot(cx);
                     let mut buffer_highlights = this
                         .document_highlights_for_position(selection.head(), &buffer)
@@ -13085,7 +13078,7 @@ impl Editor {
                 })?
             };
             if let Some(rename_range) = rename_range {
-                this.update_in(&mut cx, |this, window, cx| {
+                this.update_in(cx, |this, window, cx| {
                     let snapshot = cursor_buffer.read(cx).snapshot();
                     let rename_buffer_range = rename_range.to_offset(&snapshot);
                     let cursor_offset_in_rename_range =
@@ -13258,18 +13251,18 @@ impl Editor {
             cx,
         )?;
 
-        Some(cx.spawn_in(window, |editor, mut cx| async move {
+        Some(cx.spawn_in(window, async move |editor, cx| {
             let project_transaction = rename.await?;
             Self::open_project_transaction(
                 &editor,
                 workspace,
                 project_transaction,
                 format!("Rename: {} → {}", old_name, new_name),
-                cx.clone(),
+                cx,
             )
             .await?;
 
-            editor.update(&mut cx, |editor, cx| {
+            editor.update(cx, |editor, cx| {
                 editor.refresh_document_highlights(cx);
             })?;
             Ok(())
@@ -13416,7 +13409,7 @@ impl Editor {
             project.format(buffers, target, true, trigger, cx)
         });
 
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             let transaction = futures::select_biased! {
                 transaction = format.log_err().fuse() => transaction,
                 () = timeout => {
@@ -13426,7 +13419,7 @@ impl Editor {
             };
 
             buffer
-                .update(&mut cx, |buffer, cx| {
+                .update(cx, |buffer, cx| {
                     if let Some(transaction) = transaction {
                         if !buffer.is_singleton() {
                             buffer.push_transaction(&transaction.0, cx);
@@ -13471,7 +13464,7 @@ impl Editor {
         let apply_action = project.update(cx, |project, cx| {
             project.apply_code_action_kind(buffers, kind, true, cx)
         });
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             let transaction = futures::select_biased! {
                 () = timeout => {
                     log::warn!("timed out waiting for executing code action");
@@ -13480,7 +13473,7 @@ impl Editor {
                 transaction = apply_action.log_err().fuse() => transaction,
             };
             buffer
-                .update(&mut cx, |buffer, cx| {
+                .update(cx, |buffer, cx| {
                     // check if we need this
                     if let Some(transaction) = transaction {
                         if !buffer.is_singleton() {
@@ -13695,12 +13688,12 @@ impl Editor {
         } else {
             None
         };
-        self.inline_diagnostics_update = cx.spawn_in(window, |editor, mut cx| async move {
+        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
             if let Some(debounce) = debounce {
                 cx.background_executor().timer(debounce).await;
             }
             let Some(snapshot) = editor
-                .update(&mut cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
+                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
                 .ok()
             else {
                 return;
@@ -13741,7 +13734,7 @@ impl Editor {
                 .await;
 
             editor
-                .update(&mut cx, |editor, cx| {
+                .update(cx, |editor, cx| {
                     editor.inline_diagnostics = new_inline_diagnostics;
                     cx.notify();
                 })
@@ -14042,9 +14035,9 @@ impl Editor {
 
             self.fold_creases(fold_ranges, true, window, cx);
         } else {
-            self.toggle_fold_multiple_buffers = cx.spawn_in(window, |editor, mut cx| async move {
+            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
                 editor
-                    .update_in(&mut cx, |editor, _, cx| {
+                    .update_in(cx, |editor, _, cx| {
                         for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
                             editor.fold_buffer(buffer_id, cx);
                         }
@@ -14218,9 +14211,9 @@ impl Editor {
             let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
             self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
         } else {
-            self.toggle_fold_multiple_buffers = cx.spawn(|editor, mut cx| async move {
+            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
                 editor
-                    .update(&mut cx, |editor, cx| {
+                    .update(cx, |editor, cx| {
                         for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
                             editor.unfold_buffer(buffer_id, cx);
                         }
@@ -14507,9 +14500,9 @@ impl Editor {
         cx: &mut Context<Self>,
     ) {
         let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             task.await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let snapshot = this.buffer.read(cx).snapshot(cx);
                 let chunk_by = this
                     .diff_hunks_in_ranges(&ranges, &snapshot)
@@ -15463,34 +15456,32 @@ impl Editor {
         let permalink_task = self.get_permalink_to_line(cx);
         let workspace = self.workspace();
 
-        cx.spawn_in(window, |_, mut cx| async move {
-            match permalink_task.await {
-                Ok(permalink) => {
-                    cx.update(|_, cx| {
-                        cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
-                    })
-                    .ok();
-                }
-                Err(err) => {
-                    let message = format!("Failed to copy permalink: {err}");
+        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
+            Ok(permalink) => {
+                cx.update(|_, cx| {
+                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
+                })
+                .ok();
+            }
+            Err(err) => {
+                let message = format!("Failed to copy permalink: {err}");
 
-                    Err::<(), anyhow::Error>(err).log_err();
+                Err::<(), anyhow::Error>(err).log_err();
 
-                    if let Some(workspace) = workspace {
-                        workspace
-                            .update_in(&mut cx, |workspace, _, cx| {
-                                struct CopyPermalinkToLine;
+                if let Some(workspace) = workspace {
+                    workspace
+                        .update_in(cx, |workspace, _, cx| {
+                            struct CopyPermalinkToLine;
 
-                                workspace.show_toast(
-                                    Toast::new(
-                                        NotificationId::unique::<CopyPermalinkToLine>(),
-                                        message,
-                                    ),
-                                    cx,
-                                )
-                            })
-                            .ok();
-                    }
+                            workspace.show_toast(
+                                Toast::new(
+                                    NotificationId::unique::<CopyPermalinkToLine>(),
+                                    message,
+                                ),
+                                cx,
+                            )
+                        })
+                        .ok();
                 }
             }
         })
@@ -15520,34 +15511,32 @@ impl Editor {
         let permalink_task = self.get_permalink_to_line(cx);
         let workspace = self.workspace();
 
-        cx.spawn_in(window, |_, mut cx| async move {
-            match permalink_task.await {
-                Ok(permalink) => {
-                    cx.update(|_, cx| {
-                        cx.open_url(permalink.as_ref());
-                    })
-                    .ok();
-                }
-                Err(err) => {
-                    let message = format!("Failed to open permalink: {err}");
+        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
+            Ok(permalink) => {
+                cx.update(|_, cx| {
+                    cx.open_url(permalink.as_ref());
+                })
+                .ok();
+            }
+            Err(err) => {
+                let message = format!("Failed to open permalink: {err}");
 
-                    Err::<(), anyhow::Error>(err).log_err();
+                Err::<(), anyhow::Error>(err).log_err();
 
-                    if let Some(workspace) = workspace {
-                        workspace
-                            .update(&mut cx, |workspace, cx| {
-                                struct OpenPermalinkToLine;
+                if let Some(workspace) = workspace {
+                    workspace
+                        .update(cx, |workspace, cx| {
+                            struct OpenPermalinkToLine;
 
-                                workspace.show_toast(
-                                    Toast::new(
-                                        NotificationId::unique::<OpenPermalinkToLine>(),
-                                        message,
-                                    ),
-                                    cx,
-                                )
-                            })
-                            .ok();
-                    }
+                            workspace.show_toast(
+                                Toast::new(
+                                    NotificationId::unique::<OpenPermalinkToLine>(),
+                                    message,
+                                ),
+                                cx,
+                            )
+                        })
+                        .ok();
                 }
             }
         })
@@ -15619,8 +15608,8 @@ impl Editor {
 
         let title = multibuffer.title(cx).to_string();
 
-        cx.spawn_in(window, |_, mut cx| async move {
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+        cx.spawn_in(window, async move |_, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 Self::open_locations_in_multibuffer(
                     workspace,
                     locations,
@@ -17008,12 +16997,12 @@ impl Editor {
             }
             tasks
         });
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             for (buffer, task) in save_tasks {
                 let result = task.await;
                 if result.is_err() {
                     let Some(path) = buffer
-                        .read_with(&cx, |buffer, cx| buffer.project_path(cx))
+                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
                         .ok()
                     else {
                         continue;
@@ -17212,10 +17201,10 @@ fn get_uncommitted_diff_for_buffer(
             tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
         }
     });
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         let diffs = future::join_all(tasks).await;
         buffer
-            .update(&mut cx, |buffer, cx| {
+            .update(cx, |buffer, cx| {
                 for diff in diffs.into_iter().flatten() {
                     buffer.add_diff(diff, cx);
                 }
@@ -18069,13 +18058,13 @@ impl SemanticsProvider for Entity<Project> {
         Some(self.update(cx, |project, cx| {
             let buffer = buffer.clone();
             let task = project.prepare_rename(buffer.clone(), position, cx);
-            cx.spawn(|_, mut cx| async move {
+            cx.spawn(async move |_, cx| {
                 Ok(match task.await? {
                     PrepareRenameResponse::Success(range) => Some(range),
                     PrepareRenameResponse::InvalidPosition => None,
                     PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
                         // Fallback on using TreeSitter info to determine identifier range
-                        buffer.update(&mut cx, |buffer, _| {
+                        buffer.update(cx, |buffer, _| {
                             let snapshot = buffer.snapshot();
                             let (range, kind) = snapshot.surrounding_word(position);
                             if kind != Some(CharKind::Word) {

crates/editor/src/editor_tests.rs 🔗

@@ -9312,6 +9312,7 @@ async fn test_word_completion(cx: &mut TestAppContext) {
             .server
             .on_request::<lsp::request::Completion, _, _>(move |_, cx| {
                 let lsp_throttle_completions = lsp_throttle_completions.clone();
+                let cx = cx.clone();
                 async move {
                     if lsp_throttle_completions.load(atomic::Ordering::Acquire) {
                         cx.background_executor()

crates/editor/src/element.rs 🔗

@@ -973,10 +973,10 @@ impl EditorElement {
         };
         editor.hovered_cursors.insert(
             key.clone(),
-            cx.spawn_in(window, |editor, mut cx| async move {
+            cx.spawn_in(window, async move |editor, cx| {
                 cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
                 editor
-                    .update(&mut cx, |editor, cx| {
+                    .update(cx, |editor, cx| {
                         editor.hovered_cursors.remove(&key);
                         cx.notify();
                     })
@@ -5199,7 +5199,7 @@ impl EditorElement {
 
             editor.scrollbar_marker_state.dirty = false;
             editor.scrollbar_marker_state.pending_refresh =
-                Some(cx.spawn_in(window, |editor, mut cx| async move {
+                Some(cx.spawn_in(window, async move |editor, cx| {
                     let scrollbar_size = scrollbar_layout.hitbox.size;
                     let scrollbar_markers = cx
                         .background_spawn(async move {
@@ -5346,7 +5346,7 @@ impl EditorElement {
                         })
                         .await;
 
-                    editor.update(&mut cx, |editor, cx| {
+                    editor.update(cx, |editor, cx| {
                         editor.scrollbar_marker_state.markers = scrollbar_markers;
                         editor.scrollbar_marker_state.scrollbar_size = scrollbar_size;
                         editor.scrollbar_marker_state.pending_refresh = None;

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

@@ -363,7 +363,7 @@ impl GitBlame {
         let blame = self.project.read(cx).blame_buffer(&self.buffer, None, cx);
         let provider_registry = GitHostingProviderRegistry::default_global(cx);
 
-        self.task = cx.spawn(|this, mut cx| async move {
+        self.task = cx.spawn(async move |this, cx| {
             let result = cx
                 .background_spawn({
                     let snapshot = snapshot.clone();
@@ -386,7 +386,7 @@ impl GitBlame {
                 })
                 .await;
 
-            this.update(&mut cx, |this, cx| match result {
+            this.update(cx, |this, cx| match result {
                 Ok(None) => {
                     // Nothing to do, e.g. no repository found
                 }
@@ -417,12 +417,12 @@ impl GitBlame {
     }
 
     fn regenerate_on_edit(&mut self, cx: &mut Context<Self>) {
-        self.regenerate_on_edit_task = cx.spawn(|this, mut cx| async move {
+        self.regenerate_on_edit_task = cx.spawn(async move |this, cx| {
             cx.background_executor()
                 .timer(REGENERATE_ON_EDIT_DEBOUNCE_INTERVAL)
                 .await;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.generate(cx);
             })
         })

crates/editor/src/hover_links.rs 🔗

@@ -167,10 +167,10 @@ impl Editor {
         cx: &mut Context<Editor>,
     ) {
         let reveal_task = self.cmd_click_reveal_task(point, modifiers, window, cx);
-        cx.spawn_in(window, |editor, mut cx| async move {
+        cx.spawn_in(window, async move |editor, cx| {
             let definition_revealed = reveal_task.await.log_err().unwrap_or(Navigated::No);
             let find_references = editor
-                .update_in(&mut cx, |editor, window, cx| {
+                .update_in(cx, |editor, window, cx| {
                     if definition_revealed == Navigated::Yes {
                         return None;
                     }
@@ -529,12 +529,12 @@ pub fn show_link_definition(
     let provider = editor.semantics_provider.clone();
 
     let snapshot = snapshot.buffer_snapshot.clone();
-    hovered_link_state.task = Some(cx.spawn_in(window, |this, mut cx| {
+    hovered_link_state.task = Some(cx.spawn_in(window, async move |this, cx| {
         async move {
             let result = match &trigger_point {
                 TriggerPoint::Text(_) => {
                     if let Some((url_range, url)) = find_url(&buffer, buffer_position, cx.clone()) {
-                        this.update(&mut cx, |_, _| {
+                        this.update(cx, |_, _| {
                             let range = maybe!({
                                 let start =
                                     snapshot.anchor_in_excerpt(excerpt_id, url_range.start)?;
@@ -545,7 +545,7 @@ pub fn show_link_definition(
                         })
                         .ok()
                     } else if let Some((filename_range, filename)) =
-                        find_file(&buffer, project.clone(), buffer_position, &mut cx).await
+                        find_file(&buffer, project.clone(), buffer_position, cx).await
                     {
                         let range = maybe!({
                             let start =
@@ -589,7 +589,7 @@ pub fn show_link_definition(
                 )),
             };
 
-            this.update(&mut cx, |editor, cx| {
+            this.update(cx, |editor, cx| {
                 // Clear any existing highlights
                 editor.clear_highlights::<HoveredLinkState>(cx);
                 let Some(hovered_link_state) = editor.hovered_link_state.as_mut() else {
@@ -647,6 +647,7 @@ pub fn show_link_definition(
             Ok::<_, anyhow::Error>(())
         }
         .log_err()
+        .await
     }));
 
     editor.hovered_link_state = Some(hovered_link_state);

crates/editor/src/hover_popover.rs 🔗

@@ -149,18 +149,18 @@ pub fn hover_at_inlay(
 
         let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 
-        let task = cx.spawn_in(window, |this, mut cx| {
+        let task = cx.spawn_in(window, async move |this, cx| {
             async move {
                 cx.background_executor()
                     .timer(Duration::from_millis(hover_popover_delay))
                     .await;
-                this.update(&mut cx, |this, _| {
+                this.update(cx, |this, _| {
                     this.hover_state.diagnostic_popover = None;
                 })?;
 
-                let language_registry = project.update(&mut cx, |p, _| p.languages().clone())?;
+                let language_registry = project.update(cx, |p, _| p.languages().clone())?;
                 let blocks = vec![inlay_hover.tooltip];
-                let parsed_content = parse_blocks(&blocks, &language_registry, None, &mut cx).await;
+                let parsed_content = parse_blocks(&blocks, &language_registry, None, cx).await;
 
                 let scroll_handle = ScrollHandle::new();
                 let hover_popover = InfoPopover {
@@ -172,7 +172,7 @@ pub fn hover_at_inlay(
                     anchor: None,
                 };
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     // TODO: no background highlights happen for inlays currently
                     this.hover_state.info_popovers = vec![hover_popover];
                     cx.notify();
@@ -181,6 +181,7 @@ pub fn hover_at_inlay(
                 anyhow::Ok(())
             }
             .log_err()
+            .await
         });
 
         editor.hover_state.info_task = Some(task);
@@ -257,7 +258,7 @@ fn show_hover(
 
     let hover_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 
-    let task = cx.spawn_in(window, |this, mut cx| {
+    let task = cx.spawn_in(window, async move |this, cx| {
         async move {
             // If we need to delay, delay a set amount initially before making the lsp request
             let delay = if ignore_timeout {
@@ -375,7 +376,7 @@ fn show_hover(
                 None
             };
 
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 this.hover_state.diagnostic_popover = diagnostic_popover;
             })?;
 
@@ -409,7 +410,7 @@ fn show_hover(
             } else {
                 Vec::new()
             };
-            let snapshot = this.update_in(&mut cx, |this, window, cx| this.snapshot(window, cx))?;
+            let snapshot = this.update_in(cx, |this, window, cx| this.snapshot(window, cx))?;
             let mut hover_highlights = Vec::with_capacity(hovers_response.len());
             let mut info_popovers = Vec::with_capacity(
                 hovers_response.len() + if invisible_char.is_some() { 1 } else { 0 },
@@ -420,7 +421,7 @@ fn show_hover(
                     text: format!("Unicode character U+{:02X}", invisible as u32),
                     kind: HoverBlockKind::PlainText,
                 }];
-                let parsed_content = parse_blocks(&blocks, &language_registry, None, &mut cx).await;
+                let parsed_content = parse_blocks(&blocks, &language_registry, None, cx).await;
                 let scroll_handle = ScrollHandle::new();
                 info_popovers.push(InfoPopover {
                     symbol_range: RangeInEditor::Text(range),
@@ -459,8 +460,7 @@ fn show_hover(
 
                 let blocks = hover_result.contents;
                 let language = hover_result.language;
-                let parsed_content =
-                    parse_blocks(&blocks, &language_registry, language, &mut cx).await;
+                let parsed_content = parse_blocks(&blocks, &language_registry, language, cx).await;
                 let scroll_handle = ScrollHandle::new();
                 hover_highlights.push(range.clone());
                 info_popovers.push(InfoPopover {
@@ -473,7 +473,7 @@ fn show_hover(
                 });
             }
 
-            this.update_in(&mut cx, |editor, window, cx| {
+            this.update_in(cx, |editor, window, cx| {
                 if hover_highlights.is_empty() {
                     editor.clear_background_highlights::<HoverState>(cx);
                 } else {
@@ -493,6 +493,7 @@ fn show_hover(
             anyhow::Ok(())
         }
         .log_err()
+        .await
     });
 
     editor.hover_state.info_task = Some(task);
@@ -642,7 +643,7 @@ pub fn open_markdown_url(link: SharedString, window: &mut Window, cx: &mut App)
                         cx,
                     );
 
-                    cx.spawn_in(window, |_, mut cx| async move {
+                    cx.spawn_in(window, async move |_, cx| {
                         let item = task.await?;
                         // Ruby LSP uses URLs with #L1,1-4,4
                         // we'll just take the first number and assume it's a line number
@@ -664,7 +665,7 @@ pub fn open_markdown_url(link: SharedString, window: &mut Window, cx: &mut App)
                         let Some(editor) = cx.update(|_, cx| item.act_as::<Editor>(cx))? else {
                             return Ok(());
                         };
-                        editor.update_in(&mut cx, |editor, window, cx| {
+                        editor.update_in(cx, |editor, window, cx| {
                             editor.change_selections(
                                 Some(Autoscroll::fit()),
                                 window,

crates/editor/src/indent_guides.rs 🔗

@@ -111,16 +111,15 @@ impl Editor {
             {
                 Ok(result) => state.active_indent_range = result,
                 Err(future) => {
-                    state.pending_refresh =
-                        Some(cx.spawn_in(window, |editor, mut cx| async move {
-                            let result = cx.background_spawn(future).await;
-                            editor
-                                .update(&mut cx, |editor, _| {
-                                    editor.active_indent_guides_state.active_indent_range = result;
-                                    editor.active_indent_guides_state.pending_refresh = None;
-                                })
-                                .log_err();
-                        }));
+                    state.pending_refresh = Some(cx.spawn_in(window, async move |editor, cx| {
+                        let result = cx.background_spawn(future).await;
+                        editor
+                            .update(cx, |editor, _| {
+                                editor.active_indent_guides_state.active_indent_range = result;
+                                editor.active_indent_guides_state.pending_refresh = None;
+                            })
+                            .log_err();
+                    }));
                     return None;
                 }
             }

crates/editor/src/inlay_hint_cache.rs 🔗

@@ -412,13 +412,13 @@ impl InlayHintCache {
         } else {
             self.append_debounce
         };
-        self.refresh_task = cx.spawn(|editor, mut cx| async move {
+        self.refresh_task = cx.spawn(async move |editor, cx| {
             if let Some(debounce_duration) = debounce_duration {
                 cx.background_executor().timer(debounce_duration).await;
             }
 
             editor
-                .update(&mut cx, |editor, cx| {
+                .update(cx, |editor, cx| {
                     spawn_new_update_tasks(
                         editor,
                         reason_description,
@@ -626,8 +626,8 @@ impl InlayHintCache {
                     let server_id = *server_id;
                     cached_hint.resolve_state = ResolveState::Resolving;
                     drop(guard);
-                    cx.spawn_in(window, |editor, mut cx| async move {
-                        let resolved_hint_task = editor.update(&mut cx, |editor, cx| {
+                    cx.spawn_in(window, async move |editor, cx| {
+                        let resolved_hint_task = editor.update(cx, |editor, cx| {
                             let buffer = editor.buffer().read(cx).buffer(buffer_id)?;
                             editor.semantics_provider.as_ref()?.resolve_inlay_hint(
                                 hint_to_resolve,
@@ -639,7 +639,7 @@ impl InlayHintCache {
                         if let Some(resolved_hint_task) = resolved_hint_task {
                             let mut resolved_hint =
                                 resolved_hint_task.await.context("hint resolve task")?;
-                            editor.update(&mut cx, |editor, _| {
+                            editor.update(cx, |editor, _| {
                                 if let Some(excerpt_hints) =
                                     editor.inlay_hint_cache.hints.get(&excerpt_id)
                                 {
@@ -846,14 +846,14 @@ fn new_update_task(
     excerpt_buffer: Entity<Buffer>,
     cx: &mut Context<Editor>,
 ) -> Task<()> {
-    cx.spawn(move |editor, mut cx| async move {
+    cx.spawn(async move |editor, cx| {
         let visible_range_update_results = future::join_all(
             query_ranges
                 .visible
                 .into_iter()
                 .filter_map(|visible_range| {
                     let fetch_task = editor
-                        .update(&mut cx, |_, cx| {
+                        .update(cx, |_, cx| {
                             fetch_and_update_hints(
                                 excerpt_buffer.clone(),
                                 query,
@@ -891,7 +891,7 @@ fn new_update_task(
 
         for (range, result) in visible_range_update_results {
             if let Err(e) = result {
-                query_range_failed(&range, e, &mut cx);
+                query_range_failed(&range, e, cx);
             }
         }
 
@@ -903,7 +903,7 @@ fn new_update_task(
                 .chain(query_ranges.after_visible.into_iter())
                 .filter_map(|invisible_range| {
                     let fetch_task = editor
-                        .update(&mut cx, |_, cx| {
+                        .update(cx, |_, cx| {
                             fetch_and_update_hints(
                                 excerpt_buffer.clone(),
                                 query,
@@ -919,7 +919,7 @@ fn new_update_task(
         .await;
         for (range, result) in invisible_range_update_results {
             if let Err(e) = result {
-                query_range_failed(&range, e, &mut cx);
+                query_range_failed(&range, e, cx);
             }
         }
     })
@@ -932,10 +932,10 @@ fn fetch_and_update_hints(
     invalidate: bool,
     cx: &mut Context<Editor>,
 ) -> Task<anyhow::Result<()>> {
-    cx.spawn(|editor, mut cx| async move {
-        let buffer_snapshot = excerpt_buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
+    cx.spawn(async move |editor, cx|{
+        let buffer_snapshot = excerpt_buffer.update(cx, |buffer, _| buffer.snapshot())?;
         let (lsp_request_limiter, multi_buffer_snapshot) =
-            editor.update(&mut cx, |editor, cx| {
+            editor.update(cx, |editor, cx| {
                 let multi_buffer_snapshot =
                     editor.buffer().update(cx, |buffer, cx| buffer.snapshot(cx));
                 let lsp_request_limiter = Arc::clone(&editor.inlay_hint_cache.lsp_request_limiter);
@@ -953,7 +953,7 @@ fn fetch_and_update_hints(
         let fetch_range_to_log = fetch_range.start.to_point(&buffer_snapshot)
             ..fetch_range.end.to_point(&buffer_snapshot);
         let inlay_hints_fetch_task = editor
-            .update(&mut cx, |editor, cx| {
+            .update(cx, |editor, cx| {
                 if got_throttled {
                     let query_not_around_visible_range = match editor
                         .excerpts_for_inlay_hints_query(None, cx)
@@ -997,7 +997,7 @@ fn fetch_and_update_hints(
             .ok()
             .flatten();
 
-        let cached_excerpt_hints = editor.update(&mut cx, |editor, _| {
+        let cached_excerpt_hints = editor.update(cx, |editor, _| {
             editor
                 .inlay_hint_cache
                 .hints
@@ -1005,7 +1005,7 @@ fn fetch_and_update_hints(
                 .cloned()
         })?;
 
-        let visible_hints = editor.update(&mut cx, |editor, cx| editor.visible_inlay_hints(cx))?;
+        let visible_hints = editor.update(cx, |editor, cx| editor.visible_inlay_hints(cx))?;
         let new_hints = match inlay_hints_fetch_task {
             Some(fetch_task) => {
                 log::debug!(
@@ -1050,7 +1050,7 @@ fn fetch_and_update_hints(
             );
             log::trace!("New update: {new_update:?}");
             editor
-                .update(&mut cx, |editor,  cx| {
+                .update(cx, |editor,  cx| {
                     apply_hint_update(
                         editor,
                         new_update,

crates/editor/src/items.rs 🔗

@@ -87,7 +87,7 @@ impl FollowableItem for Editor {
                 .collect::<Result<Vec<_>>>()
         });
 
-        Some(window.spawn(cx, |mut cx| async move {
+        Some(window.spawn(cx, async move |cx| {
             let mut buffers = futures::future::try_join_all(buffers?)
                 .await
                 .debug_assert_ok("leaders don't share views for unshared buffers")?;
@@ -147,7 +147,7 @@ impl FollowableItem for Editor {
                     scroll_y: state.scroll_y,
                     ..Default::default()
                 },
-                &mut cx,
+                cx,
             )
             .await?;
 
@@ -319,8 +319,8 @@ impl FollowableItem for Editor {
     ) -> Task<Result<()>> {
         let update_view::Variant::Editor(message) = message;
         let project = project.clone();
-        cx.spawn_in(window, |this, mut cx| async move {
-            update_editor_from_message(this, project, message, &mut cx).await
+        cx.spawn_in(window, async move |this, cx| {
+            update_editor_from_message(this, project, message, cx).await
         })
     }
 
@@ -776,9 +776,9 @@ impl Item for Editor {
             .into_iter()
             .map(|handle| handle.read(cx).base_buffer().unwrap_or(handle.clone()))
             .collect::<HashSet<_>>();
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             if format {
-                this.update_in(&mut cx, |editor, window, cx| {
+                this.update_in(cx, |editor, window, cx| {
                     editor.perform_format(
                         project.clone(),
                         FormatTrigger::Save,
@@ -793,7 +793,7 @@ impl Item for Editor {
             if buffers.len() == 1 {
                 // Apply full save routine for singleton buffers, to allow to `touch` the file via the editor.
                 project
-                    .update(&mut cx, |project, cx| project.save_buffers(buffers, cx))?
+                    .update(cx, |project, cx| project.save_buffers(buffers, cx))?
                     .await?;
             } else {
                 // For multi-buffers, only format and save the buffers with changes.
@@ -801,20 +801,16 @@ impl Item for Editor {
                 // so that language servers or other downstream listeners of save events get notified.
                 let (dirty_buffers, clean_buffers) = buffers.into_iter().partition(|buffer| {
                     buffer
-                        .update(&mut cx, |buffer, _| {
-                            buffer.is_dirty() || buffer.has_conflict()
-                        })
+                        .update(cx, |buffer, _| buffer.is_dirty() || buffer.has_conflict())
                         .unwrap_or(false)
                 });
 
                 project
-                    .update(&mut cx, |project, cx| {
-                        project.save_buffers(dirty_buffers, cx)
-                    })?
+                    .update(cx, |project, cx| project.save_buffers(dirty_buffers, cx))?
                     .await?;
                 for buffer in clean_buffers {
                     buffer
-                        .update(&mut cx, |buffer, cx| {
+                        .update(cx, |buffer, cx| {
                             let version = buffer.saved_version().clone();
                             let mtime = buffer.saved_mtime();
                             buffer.did_save(version, mtime, cx);
@@ -859,13 +855,13 @@ impl Item for Editor {
         let buffers = self.buffer.read(cx).all_buffers();
         let reload_buffers =
             project.update(cx, |project, cx| project.reload_buffers(buffers, true, cx));
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let transaction = reload_buffers.log_err().await;
-            this.update(&mut cx, |editor, cx| {
+            this.update(cx, |editor, cx| {
                 editor.request_autoscroll(Autoscroll::fit(), cx)
             })?;
             buffer
-                .update(&mut cx, |buffer, cx| {
+                .update(cx, |buffer, cx| {
                     if let Some(transaction) = transaction {
                         if !buffer.is_singleton() {
                             buffer.push_transaction(&transaction.0, cx);
@@ -996,7 +992,9 @@ impl SerializableItem for Editor {
         window: &mut Window,
         cx: &mut App,
     ) -> Task<Result<()>> {
-        window.spawn(cx, |_| DB.delete_unloaded_items(workspace_id, alive_items))
+        window.spawn(cx, async move |_| {
+            DB.delete_unloaded_items(workspace_id, alive_items).await
+        })
     }
 
     fn deserialize(
@@ -1040,11 +1038,11 @@ impl SerializableItem for Editor {
                 contents: Some(contents),
                 language,
                 ..
-            } => window.spawn(cx, |mut cx| {
+            } => window.spawn(cx, {
                 let project = project.clone();
-                async move {
+                async move |cx| {
                     let language_registry =
-                        project.update(&mut cx, |project, _| project.languages().clone())?;
+                        project.update(cx, |project, _| project.languages().clone())?;
 
                     let language = if let Some(language_name) = language {
                         // We don't fail here, because we'd rather not set the language if the name changed
@@ -1059,11 +1057,11 @@ impl SerializableItem for Editor {
 
                     // First create the empty buffer
                     let buffer = project
-                        .update(&mut cx, |project, cx| project.create_buffer(cx))?
+                        .update(cx, |project, cx| project.create_buffer(cx))?
                         .await?;
 
                     // Then set the text so that the dirty bit is set correctly
-                    buffer.update(&mut cx, |buffer, cx| {
+                    buffer.update(cx, |buffer, cx| {
                         buffer.set_language_registry(language_registry);
                         if let Some(language) = language {
                             buffer.set_language(Some(language), cx);
@@ -1102,7 +1100,7 @@ impl SerializableItem for Editor {
 
                 match project_item {
                     Some(project_item) => {
-                        window.spawn(cx, |mut cx| async move {
+                        window.spawn(cx, async move |cx| {
                             let (_, project_item) = project_item.await?;
                             let buffer = project_item.downcast::<Buffer>().map_err(|_| {
                                 anyhow!("Project item at stored path was not a buffer")
@@ -1114,7 +1112,7 @@ impl SerializableItem for Editor {
                             // simple, because we don't have to persist all of the metadata that we get
                             // by loading the file (git diff base, ...).
                             if let Some(buffer_text) = contents {
-                                buffer.update(&mut cx, |buffer, cx| {
+                                buffer.update(cx, |buffer, cx| {
                                     // If we did restore an mtime, we want to store it on the buffer
                                     // so that the next edit will mark the buffer as dirty/conflicted.
                                     if mtime.is_some() {
@@ -1166,9 +1164,9 @@ impl SerializableItem for Editor {
                                 cx,
                             )
                         });
-                        window.spawn(cx, |mut cx| async move {
+                        window.spawn(cx, async move |cx| {
                             let editor = open_by_abs_path?.await?.downcast::<Editor>().with_context(|| format!("Failed to downcast to Editor after opening abs path {abs_path:?}"))?;
-                            editor.update_in(&mut cx, |editor, window, cx| {
+                            editor.update_in(cx, |editor, window, cx| {
                                 editor.read_selections_from_db(item_id, workspace_id, window, cx);
                                 editor.read_scroll_position_from_db(item_id, workspace_id, window, cx);
                             })?;
@@ -1228,7 +1226,7 @@ impl SerializableItem for Editor {
 
         let snapshot = buffer.read(cx).snapshot();
 
-        Some(cx.spawn_in(window, |_this, cx| async move {
+        Some(cx.spawn_in(window, async move |_this, cx| {
             cx.background_spawn(async move {
                 let (contents, language) = if serialize_dirty_buffers && is_dirty {
                     let contents = snapshot.text();

crates/editor/src/jsx_tag_auto_close.rs 🔗

@@ -434,7 +434,7 @@ pub(crate) fn handle_from(
         let (buffer_version_initial, mut buffer_parse_status_rx) =
             buffer.read_with(cx, |buffer, _| (buffer.version(), buffer.parse_status()));
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let Some(buffer_parse_status) = buffer_parse_status_rx.recv().await.ok() else {
                 return Some(());
             };
@@ -445,7 +445,7 @@ pub(crate) fn handle_from(
                 };
             }
 
-            let buffer_snapshot = buffer.read_with(&cx, |buf, _| buf.snapshot()).ok()?;
+            let buffer_snapshot = buffer.read_with(cx, |buf, _| buf.snapshot()).ok()?;
 
             let Some(edit_behavior_state) =
                 should_auto_close(&buffer_snapshot, &edited_ranges, &jsx_tag_auto_close_config)
@@ -456,7 +456,7 @@ pub(crate) fn handle_from(
             let ensure_no_edits_since_start = || -> Option<()> {
                 // <div>wef,wefwef
                 let has_edits_since_start = this
-                    .read_with(&cx, |this, cx| {
+                    .read_with(cx, |this, cx| {
                         this.buffer.read_with(cx, |buffer, cx| {
                             buffer.buffer(buffer_id).map_or(true, |buffer| {
                                 buffer.read_with(cx, |buffer, _| {
@@ -506,7 +506,7 @@ pub(crate) fn handle_from(
             ensure_no_edits_since_start()?;
 
             let multi_buffer_snapshot = this
-                .read_with(&cx, |this, cx| {
+                .read_with(cx, |this, cx| {
                     this.buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx))
                 })
                 .ok()?;
@@ -516,7 +516,7 @@ pub(crate) fn handle_from(
 
             {
                 let selections = this
-                    .read_with(&cx, |this, _| this.selections.disjoint_anchors().clone())
+                    .read_with(cx, |this, _| this.selections.disjoint_anchors().clone())
                     .ok()?;
                 for selection in selections.iter() {
                     let Some(selection_buffer_offset_head) =
@@ -576,14 +576,14 @@ pub(crate) fn handle_from(
             }
 
             buffer
-                .update(&mut cx, |buffer, cx| {
+                .update(cx, |buffer, cx| {
                     buffer.edit(edits, None, cx);
                 })
                 .ok()?;
 
             if any_selections_need_update {
                 let multi_buffer_snapshot = this
-                    .read_with(&cx, |this, cx| {
+                    .read_with(cx, |this, cx| {
                         this.buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx))
                     })
                     .ok()?;
@@ -601,7 +601,7 @@ pub(crate) fn handle_from(
                         selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot))
                     })
                     .collect::<Vec<_>>();
-                this.update_in(&mut cx, |this, window, cx| {
+                this.update_in(cx, |this, window, cx| {
                     this.change_selections_inner(None, false, window, cx, |s| {
                         s.select(base_selections);
                     });

crates/editor/src/linked_editing_ranges.rs 🔗

@@ -49,12 +49,12 @@ pub(super) fn refresh_linked_ranges(
     }
     let project = editor.project.as_ref()?.downgrade();
 
-    editor.linked_editing_range_task = Some(cx.spawn_in(window, |editor, mut cx| async move {
+    editor.linked_editing_range_task = Some(cx.spawn_in(window, async move |editor, cx| {
         cx.background_executor().timer(UPDATE_DEBOUNCE).await;
 
         let mut applicable_selections = Vec::new();
         editor
-            .update(&mut cx, |editor, cx| {
+            .update(cx, |editor, cx| {
                 let selections = editor.selections.all::<usize>(cx);
                 let snapshot = editor.buffer.read(cx).snapshot(cx);
                 let buffer = editor.buffer.read(cx);
@@ -84,7 +84,7 @@ pub(super) fn refresh_linked_ranges(
         }
 
         let highlights = project
-            .update(&mut cx, |project, cx| {
+            .update(cx, |project, cx| {
                 let mut linked_edits_tasks = vec![];
 
                 for (buffer, start, end) in &applicable_selections {
@@ -133,7 +133,7 @@ pub(super) fn refresh_linked_ranges(
         let highlights = futures::future::join_all(highlights).await;
 
         editor
-            .update(&mut cx, |this, cx| {
+            .update(cx, |this, cx| {
                 this.linked_edit_ranges.0.clear();
                 if this.pending_rename.is_some() {
                     return;

crates/editor/src/proposed_changes_editor.rs 🔗

@@ -77,7 +77,7 @@ impl ProposedChangesEditor {
             title: title.into(),
             buffer_entries: Vec::new(),
             recalculate_diffs_tx,
-            _recalculate_diffs_task: cx.spawn_in(window, |this, mut cx| async move {
+            _recalculate_diffs_task: cx.spawn_in(window, async move |this, cx| {
                 let mut buffers_to_diff = HashSet::default();
                 while let Some(mut recalculate_diff) = recalculate_diffs_rx.next().await {
                     buffers_to_diff.insert(recalculate_diff.buffer);
@@ -99,7 +99,7 @@ impl ProposedChangesEditor {
                     }
 
                     let recalculate_diff_futures = this
-                        .update(&mut cx, |this, cx| {
+                        .update(cx, |this, cx| {
                             buffers_to_diff
                                 .drain()
                                 .filter_map(|buffer| {

crates/editor/src/rust_analyzer_ext.rs 🔗

@@ -66,7 +66,7 @@ pub fn expand_macro_recursively(
             cx,
         )
     });
-    cx.spawn_in(window, |_editor, mut cx| async move {
+    cx.spawn_in(window, async move |_editor, cx| {
         let macro_expansion = expand_macro_task.await.context("expand macro")?;
         if macro_expansion.is_empty() {
             log::info!("Empty macro expansion for position {position:?}");
@@ -74,9 +74,9 @@ pub fn expand_macro_recursively(
         }
 
         let buffer = project
-            .update(&mut cx, |project, cx| project.create_buffer(cx))?
+            .update(cx, |project, cx| project.create_buffer(cx))?
             .await?;
-        workspace.update_in(&mut cx, |workspace, window, cx| {
+        workspace.update_in(cx, |workspace, window, cx| {
             buffer.update(cx, |buffer, cx| {
                 buffer.set_text(macro_expansion.expansion, cx);
                 buffer.set_language(Some(rust_language), cx);
@@ -134,7 +134,7 @@ pub fn open_docs(editor: &mut Editor, _: &OpenDocs, window: &mut Window, cx: &mu
         )
     });
 
-    cx.spawn_in(window, |_editor, mut cx| async move {
+    cx.spawn_in(window, async move |_editor, cx| {
         let docs_urls = open_docs_task.await.context("open docs")?;
         if docs_urls.is_empty() {
             log::debug!("Empty docs urls for position {position:?}");
@@ -143,7 +143,7 @@ pub fn open_docs(editor: &mut Editor, _: &OpenDocs, window: &mut Window, cx: &mu
             log::debug!("{:?}", docs_urls);
         }
 
-        workspace.update(&mut cx, |_workspace, cx| {
+        workspace.update(cx, |_workspace, cx| {
             // Check if the local document exists, otherwise fallback to the online document.
             // Open with the default browser.
             if let Some(local_url) = docs_urls.local {

crates/editor/src/scroll.rs 🔗

@@ -341,12 +341,12 @@ impl ScrollManager {
         }
 
         if cx.default_global::<ScrollbarAutoHide>().0 {
-            self.hide_scrollbar_task = Some(cx.spawn_in(window, |editor, mut cx| async move {
+            self.hide_scrollbar_task = Some(cx.spawn_in(window, async move |editor, cx| {
                 cx.background_executor()
                     .timer(SCROLLBAR_SHOW_INTERVAL)
                     .await;
                 editor
-                    .update(&mut cx, |editor, cx| {
+                    .update(cx, |editor, cx| {
                         editor.scroll_manager.show_scrollbars = false;
                         cx.notify();
                     })
@@ -425,9 +425,9 @@ impl Editor {
         let opened_first_time = self.scroll_manager.visible_line_count.is_none();
         self.scroll_manager.visible_line_count = Some(lines);
         if opened_first_time {
-            cx.spawn_in(window, |editor, mut cx| async move {
+            cx.spawn_in(window, async move |editor, cx| {
                 editor
-                    .update(&mut cx, |editor, cx| {
+                    .update(cx, |editor, cx| {
                         editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx)
                     })
                     .ok()

crates/editor/src/scroll/actions.rs 🔗

@@ -77,12 +77,12 @@ impl Editor {
         );
 
         self.next_scroll_position = self.next_scroll_position.next();
-        self._scroll_cursor_center_top_bottom_task = cx.spawn(|editor, mut cx| async move {
+        self._scroll_cursor_center_top_bottom_task = cx.spawn(async move |editor, cx| {
             cx.background_executor()
                 .timer(SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT)
                 .await;
             editor
-                .update(&mut cx, |editor, _| {
+                .update(cx, |editor, _| {
                     editor.next_scroll_position = NextScrollCursorCenterTopBottom::default();
                 })
                 .ok();

crates/editor/src/signature_help.rs 🔗

@@ -179,10 +179,10 @@ impl Editor {
         let language = self.language_at(position, cx);
 
         self.signature_help_state
-            .set_task(cx.spawn_in(window, move |editor, mut cx| async move {
+            .set_task(cx.spawn_in(window, async move |editor, cx| {
                 let signature_help = task.await;
                 editor
-                    .update(&mut cx, |editor, cx| {
+                    .update(cx, |editor, cx| {
                         let Some(mut signature_help) = signature_help.into_iter().next() else {
                             editor
                                 .signature_help_state

crates/evals/src/eval.rs 🔗

@@ -116,8 +116,8 @@ fn main() -> Result<()> {
                     .detach();
             }
             Commands::Run { repo } => {
-                cx.spawn(|mut cx| async move {
-                    if let Err(err) = run_evaluation(repo, &executor, &mut cx).await {
+                cx.spawn(async move |cx| {
+                    if let Err(err) = run_evaluation(repo, &executor, cx).await {
                         eprintln!("Error: {}", err);
                         exit(1);
                     }

crates/extension_host/src/extension_host.rs 🔗

@@ -305,21 +305,20 @@ impl ExtensionStore {
             reload_future = Some(this.reload(None, cx));
         }
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             if let Some(future) = reload_future {
                 future.await;
             }
-            this.update(&mut cx, |this, cx| this.auto_install_extensions(cx))
-                .ok();
-            this.update(&mut cx, |this, cx| this.check_for_updates(cx))
+            this.update(cx, |this, cx| this.auto_install_extensions(cx))
                 .ok();
+            this.update(cx, |this, cx| this.check_for_updates(cx)).ok();
         })
         .detach();
 
         // Perform all extension loading in a single task to ensure that we
         // never attempt to simultaneously load/unload extensions from multiple
         // parallel tasks.
-        this.tasks.push(cx.spawn(|this, mut cx| {
+        this.tasks.push(cx.spawn(async move |this, cx| {
             async move {
                 load_initial_extensions.await;
 
@@ -330,14 +329,14 @@ impl ExtensionStore {
                         _ = debounce_timer => {
                             if index_changed {
                                 let index = this
-                                    .update(&mut cx, |this, cx| this.rebuild_extension_index(cx))?
+                                    .update(cx, |this, cx| this.rebuild_extension_index(cx))?
                                     .await;
-                                this.update(&mut cx, |this, cx| this.extensions_updated(index, cx))?
+                                this.update( cx, |this, cx| this.extensions_updated(index, cx))?
                                     .await;
                                 index_changed = false;
                             }
 
-                            Self::update_ssh_clients(&this, &mut cx).await?;
+                            Self::update_ssh_clients(&this, cx).await?;
                         }
                         _ = connection_registered_rx.next() => {
                             debounce_timer = cx
@@ -347,7 +346,7 @@ impl ExtensionStore {
                         }
                         extension_id = reload_rx.next() => {
                             let Some(extension_id) = extension_id else { break; };
-                            this.update(&mut cx, |this, _| {
+                            this.update( cx, |this, _| {
                                 this.modified_extensions.extend(extension_id);
                             })?;
                             index_changed = true;
@@ -362,6 +361,7 @@ impl ExtensionStore {
                 anyhow::Ok(())
             }
             .map(drop)
+            .await;
         }));
 
         // Watch the installed extensions directory for changes. Whenever changes are
@@ -542,9 +542,9 @@ impl ExtensionStore {
             ],
             cx,
         );
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let extensions = task.await?;
-            this.update(&mut cx, |this, _cx| {
+            this.update(cx, |this, _cx| {
                 extensions
                     .into_iter()
                     .filter(|extension| {
@@ -589,9 +589,9 @@ impl ExtensionStore {
             .cloned()
             .collect::<Vec<_>>();
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             for extension_id in extensions_to_install {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.install_latest_extension(extension_id.clone(), cx);
                 })
                 .ok();
@@ -602,10 +602,8 @@ impl ExtensionStore {
 
     pub fn check_for_updates(&mut self, cx: &mut Context<Self>) {
         let task = self.fetch_extensions_with_update_available(cx);
-        cx.spawn(move |this, mut cx| async move {
-            Self::upgrade_extensions(this, task.await?, &mut cx).await
-        })
-        .detach();
+        cx.spawn(async move |this, cx| Self::upgrade_extensions(this, task.await?, cx).await)
+            .detach();
     }
 
     async fn upgrade_extensions(
@@ -646,7 +644,7 @@ impl ExtensionStore {
     ) -> Task<Result<Vec<ExtensionMetadata>>> {
         let url = self.http_client.build_zed_api_url(path, query);
         let http_client = self.http_client.clone();
-        cx.spawn(move |_, _| async move {
+        cx.spawn(async move |_, _| {
             let mut response = http_client
                 .get(url?.as_ref(), AsyncBody::empty(), true)
                 .await?;
@@ -698,17 +696,12 @@ impl ExtensionStore {
         };
         cx.notify();
 
-        cx.spawn(move |this, mut cx| async move {
-            let _finish = util::defer({
-                let this = this.clone();
-                let mut cx = cx.clone();
+        cx.spawn(async move |this, cx| {
+            let _finish = cx.on_drop(&this, {
                 let extension_id = extension_id.clone();
-                move || {
-                    this.update(&mut cx, |this, cx| {
-                        this.outstanding_operations.remove(extension_id.as_ref());
-                        cx.notify();
-                    })
-                    .ok();
+                move |this, cx| {
+                    this.outstanding_operations.remove(extension_id.as_ref());
+                    cx.notify();
                 }
             });
 
@@ -744,13 +737,13 @@ impl ExtensionStore {
             let decompressed_bytes = GzipDecoder::new(BufReader::new(tar_gz_bytes.as_slice()));
             let archive = Archive::new(decompressed_bytes);
             archive.unpack(extension_dir).await?;
-            this.update(&mut cx, |this, cx| {
+            this.update( cx, |this, cx| {
                 this.reload(Some(extension_id.clone()), cx)
             })?
             .await;
 
             if let ExtensionOperation::Install = operation {
-                this.update(&mut cx, |_, cx| {
+                this.update( cx, |_, cx| {
                     cx.emit(Event::ExtensionInstalled(extension_id));
                 })
                 .ok();
@@ -835,17 +828,12 @@ impl ExtensionStore {
             btree_map::Entry::Vacant(e) => e.insert(ExtensionOperation::Remove),
         };
 
-        cx.spawn(move |this, mut cx| async move {
-            let _finish = util::defer({
-                let this = this.clone();
-                let mut cx = cx.clone();
+        cx.spawn(async move |this, cx| {
+            let _finish = cx.on_drop(&this, {
                 let extension_id = extension_id.clone();
-                move || {
-                    this.update(&mut cx, |this, cx| {
-                        this.outstanding_operations.remove(extension_id.as_ref());
-                        cx.notify();
-                    })
-                    .ok();
+                move |this, cx| {
+                    this.outstanding_operations.remove(extension_id.as_ref());
+                    cx.notify();
                 }
             });
 
@@ -867,8 +855,7 @@ impl ExtensionStore {
             )
             .await?;
 
-            this.update(&mut cx, |this, cx| this.reload(None, cx))?
-                .await;
+            this.update(cx, |this, cx| this.reload(None, cx))?.await;
             anyhow::Ok(())
         })
         .detach_and_log_err(cx)
@@ -883,12 +870,12 @@ impl ExtensionStore {
         let fs = self.fs.clone();
         let builder = self.builder.clone();
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let mut extension_manifest =
                 ExtensionManifest::load(fs.clone(), &extension_source_path).await?;
             let extension_id = extension_manifest.id.clone();
 
-            if !this.update(&mut cx, |this, cx| {
+            if !this.update(cx, |this, cx| {
                 match this.outstanding_operations.entry(extension_id.clone()) {
                     btree_map::Entry::Occupied(_) => return false,
                     btree_map::Entry::Vacant(e) => e.insert(ExtensionOperation::Remove),
@@ -899,16 +886,11 @@ impl ExtensionStore {
                 return Ok(());
             }
 
-            let _finish = util::defer({
-                let this = this.clone();
-                let mut cx = cx.clone();
+            let _finish = cx.on_drop(&this, {
                 let extension_id = extension_id.clone();
-                move || {
-                    this.update(&mut cx, |this, cx| {
-                        this.outstanding_operations.remove(extension_id.as_ref());
-                        cx.notify();
-                    })
-                    .ok();
+                move |this, cx| {
+                    this.outstanding_operations.remove(extension_id.as_ref());
+                    cx.notify();
                 }
             });
 
@@ -945,8 +927,7 @@ impl ExtensionStore {
             fs.create_symlink(output_path, extension_source_path)
                 .await?;
 
-            this.update(&mut cx, |this, cx| this.reload(None, cx))?
-                .await;
+            this.update(cx, |this, cx| this.reload(None, cx))?.await;
             Ok(())
         })
     }
@@ -973,16 +954,16 @@ impl ExtensionStore {
                 .await
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = compile.await;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.outstanding_operations.remove(&extension_id);
                 cx.notify();
             })?;
 
             if result.is_ok() {
-                this.update(&mut cx, |this, cx| this.reload(Some(extension_id), cx))?
+                this.update(cx, |this, cx| this.reload(Some(extension_id), cx))?
                     .await;
             }
 
@@ -1216,7 +1197,7 @@ impl ExtensionStore {
         cx.notify();
         cx.emit(Event::ExtensionsUpdated);
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             cx.background_spawn({
                 let fs = fs.clone();
                 async move {
@@ -1263,14 +1244,14 @@ impl ExtensionStore {
                 if let Some(wasm_extension) = wasm_extension.log_err() {
                     wasm_extensions.push((extension.manifest.clone(), wasm_extension));
                 } else {
-                    this.update(&mut cx, |_, cx| {
+                    this.update(cx, |_, cx| {
                         cx.emit(Event::ExtensionFailedToLoad(extension.manifest.id.clone()))
                     })
                     .ok();
                 }
             }
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.reload_complete_senders.clear();
 
                 for (manifest, wasm_extension) in &wasm_extensions {

crates/extension_host/src/headless_host.rs 🔗

@@ -84,20 +84,17 @@ impl HeadlessExtensionStore {
             })
             .collect();
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let mut missing = Vec::new();
 
             for extension_id in to_remove {
                 log::info!("removing extension: {}", extension_id);
-                this.update(&mut cx, |this, cx| {
-                    this.uninstall_extension(&extension_id, cx)
-                })?
-                .await?;
+                this.update(cx, |this, cx| this.uninstall_extension(&extension_id, cx))?
+                    .await?;
             }
 
             for extension in to_load {
-                if let Err(e) = Self::load_extension(this.clone(), extension.clone(), &mut cx).await
-                {
+                if let Err(e) = Self::load_extension(this.clone(), extension.clone(), cx).await {
                     log::info!("failed to load extension: {}, {:?}", extension.id, e);
                     missing.push(extension)
                 } else if extension.dev {
@@ -218,7 +215,7 @@ impl HeadlessExtensionStore {
 
         let path = self.extension_dir.join(&extension_id.to_string());
         let fs = self.fs.clone();
-        cx.spawn(|_, _| async move {
+        cx.spawn(async move |_, _| {
             fs.remove_dir(
                 &path,
                 RemoveOptions {
@@ -239,9 +236,9 @@ impl HeadlessExtensionStore {
         let path = self.extension_dir.join(&extension.id);
         let fs = self.fs.clone();
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             if fs.is_dir(&path).await {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.uninstall_extension(&extension.id.clone().into(), cx)
                 })?
                 .await?;
@@ -250,7 +247,7 @@ impl HeadlessExtensionStore {
             fs.rename(&tmp_path, &path, RenameOptions::default())
                 .await?;
 
-            Self::load_extension(this, extension, &mut cx).await
+            Self::load_extension(this, extension, cx).await
         })
     }
 

crates/extension_host/src/wasm_host.rs 🔗

@@ -334,9 +334,9 @@ impl WasmHost {
         cx: &mut App,
     ) -> Arc<Self> {
         let (tx, mut rx) = mpsc::unbounded::<MainThreadCall>();
-        let task = cx.spawn(|mut cx| async move {
+        let task = cx.spawn(async move |cx| {
             while let Some(message) = rx.next().await {
-                message(&mut cx).await;
+                message(cx).await;
             }
         });
         Arc::new(Self {

crates/extensions_ui/src/extension_version_selector.rs 🔗

@@ -129,7 +129,7 @@ impl PickerDelegate for ExtensionVersionSelectorDelegate {
             })
             .collect::<Vec<_>>();
 
-        cx.spawn_in(window, move |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let matches = if query.is_empty() {
                 candidates
                     .into_iter()
@@ -153,7 +153,7 @@ impl PickerDelegate for ExtensionVersionSelectorDelegate {
                 .await
             };
 
-            this.update(&mut cx, |this, _cx| {
+            this.update(cx, |this, _cx| {
                 this.delegate.matches = matches;
                 this.delegate.selected_index = this
                     .delegate

crates/extensions_ui/src/extensions_ui.rs 🔗

@@ -77,14 +77,14 @@ pub fn init(cx: &mut App) {
 
                 let workspace_handle = cx.entity().downgrade();
                 window
-                    .spawn(cx, |mut cx| async move {
+                    .spawn(cx, async move |cx| {
                         let extension_path =
                             match Flatten::flatten(prompt.await.map_err(|e| e.into())) {
                                 Ok(Some(mut paths)) => paths.pop()?,
                                 Ok(None) => return None,
                                 Err(err) => {
                                     workspace_handle
-                                        .update(&mut cx, |workspace, cx| {
+                                        .update(cx, |workspace, cx| {
                                             workspace.show_portal_error(err.to_string(), cx);
                                         })
                                         .ok();
@@ -93,7 +93,7 @@ pub fn init(cx: &mut App) {
                             };
 
                         let install_task = store
-                            .update(&mut cx, |store, cx| {
+                            .update(cx, |store, cx| {
                                 store.install_dev_extension(extension_path, cx)
                             })
                             .ok()?;
@@ -102,7 +102,7 @@ pub fn init(cx: &mut App) {
                             Ok(_) => {}
                             Err(err) => {
                                 workspace_handle
-                                    .update(&mut cx, |workspace, cx| {
+                                    .update(cx, |workspace, cx| {
                                         workspace.show_error(
                                             &err.context("failed to install dev extension"),
                                             cx,
@@ -399,7 +399,7 @@ impl ExtensionsPage {
             store.fetch_extensions(search.as_deref(), provides_filter.as_ref(), cx)
         });
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let dev_extensions = if let Some(search) = search {
                 let match_candidates = dev_extensions
                     .iter()
@@ -425,7 +425,7 @@ impl ExtensionsPage {
             };
 
             let fetch_result = remote_extensions.await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 cx.notify();
                 this.dev_extension_entries = dev_extensions;
                 this.is_fetching_extensions = false;
@@ -768,8 +768,8 @@ impl ExtensionsPage {
             return;
         };
 
-        cx.spawn_in(window, move |this, mut cx| async move {
-            let extension_versions_task = this.update(&mut cx, |_, cx| {
+        cx.spawn_in(window, async move |this, cx| {
+            let extension_versions_task = this.update(cx, |_, cx| {
                 let extension_store = ExtensionStore::global(cx);
 
                 extension_store.update(cx, |store, cx| {
@@ -779,7 +779,7 @@ impl ExtensionsPage {
 
             let extension_versions = extension_versions_task.await?;
 
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 let fs = workspace.project().read(cx).fs().clone();
                 workspace.toggle_modal(window, cx, |window, cx| {
                     let delegate = ExtensionVersionSelectorDelegate::new(
@@ -969,9 +969,9 @@ impl ExtensionsPage {
     }
 
     fn fetch_extensions_debounced(&mut self, cx: &mut Context<ExtensionsPage>) {
-        self.extension_fetch_task = Some(cx.spawn(|this, mut cx| async move {
+        self.extension_fetch_task = Some(cx.spawn(async move |this, cx| {
             let search = this
-                .update(&mut cx, |this, cx| this.search_query(cx))
+                .update(cx, |this, cx| this.search_query(cx))
                 .ok()
                 .flatten();
 
@@ -987,7 +987,7 @@ impl ExtensionsPage {
                     .await;
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.fetch_extensions(search, Some(BTreeSet::from_iter(this.provides_filter)), cx);
             })
             .ok();

crates/feature_flags/src/feature_flags.rs 🔗

@@ -252,7 +252,7 @@ impl FeatureFlagAppExt for App {
     fn wait_for_flag_or_timeout<T: FeatureFlag>(&mut self, timeout: Duration) -> Task<bool> {
         let wait_for_flag = self.wait_for_flag::<T>();
 
-        self.spawn(|_cx| async move {
+        self.spawn(async move |_cx| {
             let mut wait_for_flag = wait_for_flag.fuse();
             let mut timeout = FutureExt::fuse(smol::Timer::after(timeout));
 

crates/feedback/src/feedback.rs 🔗

@@ -48,7 +48,7 @@ pub fn init(cx: &mut App) {
             .register_action(|_, _: &CopySystemSpecsIntoClipboard, window, cx| {
                 let specs = SystemSpecs::new(window, cx);
 
-                cx.spawn_in(window, |_, mut cx| async move {
+                cx.spawn_in(window, async move |_, cx| {
                     let specs = specs.await.to_string();
 
                     cx.update(|_, cx| {
@@ -67,7 +67,7 @@ pub fn init(cx: &mut App) {
                 .detach();
             })
             .register_action(|_, _: &RequestFeature, window, cx| {
-                cx.spawn_in(window, |_, mut cx| async move {
+                cx.spawn_in(window, async move |_, cx| {
                     cx.update(|_, cx| {
                         cx.open_url(&request_feature_url());
                     })
@@ -77,7 +77,7 @@ pub fn init(cx: &mut App) {
             })
             .register_action(move |_, _: &FileBugReport, window, cx| {
                 let specs = SystemSpecs::new(window, cx);
-                cx.spawn_in(window, |_, mut cx| async move {
+                cx.spawn_in(window, async move |_, cx| {
                     let specs = specs.await;
                     cx.update(|_, cx| {
                         cx.open_url(&file_bug_report_url(&specs));

crates/feedback/src/feedback_modal.rs 🔗

@@ -115,9 +115,9 @@ impl ModalView for FeedbackModal {
             cx,
         );
 
-        cx.spawn_in(window, move |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             if answer.await.ok() == Some(0) {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.dismiss_modal = true;
                     cx.emit(DismissEvent)
                 })
@@ -144,14 +144,14 @@ impl FeedbackModal {
                     let project = workspace.project().clone();
 
                     let system_specs = SystemSpecs::new(window, cx);
-                    cx.spawn_in(window, |workspace, mut cx| async move {
+                    cx.spawn_in(window, async move |workspace, cx| {
                         let markdown = markdown.await.log_err();
-                        let buffer = project.update(&mut cx, |project, cx| {
+                        let buffer = project.update(cx, |project, cx| {
                             project.create_local_buffer("", markdown, cx)
                         })?;
                         let system_specs = system_specs.await;
 
-                        workspace.update_in(&mut cx, |workspace, window, cx| {
+                        workspace.update_in(cx, |workspace, window, cx| {
                             workspace.toggle_modal(window, cx, move |window, cx| {
                                 FeedbackModal::new(system_specs, project, buffer, window, cx)
                             });
@@ -240,10 +240,10 @@ impl FeedbackModal {
         );
         let client = Client::global(cx).clone();
         let specs = self.system_specs.clone();
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let answer = answer.await.ok();
             if answer == Some(0) {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.submission_state = Some(SubmissionState::CannotSubmit {
                         reason: CannotSubmitReason::AwaitingSubmission,
                     });
@@ -256,7 +256,7 @@ impl FeedbackModal {
 
                 match res {
                     Ok(_) => {
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             this.dismiss_modal = true;
                             cx.notify();
                             cx.emit(DismissEvent)
@@ -265,7 +265,7 @@ impl FeedbackModal {
                     }
                     Err(error) => {
                         log::error!("{}", error);
-                        this.update_in(&mut cx, |this, window, cx| {
+                        this.update_in(cx, |this, window, cx| {
                             let prompt = window.prompt(
                                 PromptLevel::Critical,
                                 FEEDBACK_SUBMISSION_ERROR_TEXT,
@@ -273,7 +273,7 @@ impl FeedbackModal {
                                 &["OK"],
                                 cx,
                             );
-                            cx.spawn_in(window, |_, _cx| async move {
+                            cx.spawn_in(window, async move |_, _cx| {
                                 prompt.await.ok();
                             })
                             .detach();
@@ -369,20 +369,18 @@ impl FeedbackModal {
     fn update_email_in_store(&self, window: &mut Window, cx: &mut Context<Self>) {
         let email = self.email_address_editor.read(cx).text_option(cx);
 
-        cx.spawn_in(window, |_, _| async move {
-            match email {
-                Some(email) => {
-                    KEY_VALUE_STORE
-                        .write_kvp(DATABASE_KEY_NAME.to_string(), email)
-                        .await
-                        .ok();
-                }
-                None => {
-                    KEY_VALUE_STORE
-                        .delete_kvp(DATABASE_KEY_NAME.to_string())
-                        .await
-                        .ok();
-                }
+        cx.spawn_in(window, async move |_, _| match email {
+            Some(email) => {
+                KEY_VALUE_STORE
+                    .write_kvp(DATABASE_KEY_NAME.to_string(), email)
+                    .await
+                    .ok();
+            }
+            None => {
+                KEY_VALUE_STORE
+                    .delete_kvp(DATABASE_KEY_NAME.to_string())
+                    .await
+                    .ok();
             }
         })
         .detach();
@@ -516,9 +514,8 @@ impl Render for FeedbackModal {
                                     .style(ButtonStyle::Subtle)
                                     .color(Color::Muted)
                                     .on_click(cx.listener(move |_, _, window, cx| {
-                                        cx.spawn_in(window, |this, mut cx| async move {
-                                            this.update(&mut cx, |_, cx| cx.emit(DismissEvent))
-                                                .ok();
+                                        cx.spawn_in(window, async move |this, cx| {
+                                            this.update(cx, |_, cx| cx.emit(DismissEvent)).ok();
                                         })
                                         .detach();
                                     })),

crates/file_finder/src/file_finder.rs 🔗

@@ -145,11 +145,11 @@ impl FileFinder {
                 }
             })
             .collect::<Vec<_>>();
-        cx.spawn_in(window, move |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             let history_items = join_all(history_items).await.into_iter().flatten();
 
             workspace
-                .update_in(&mut cx, |workspace, window, cx| {
+                .update_in(cx, |workspace, window, cx| {
                     let project = workspace.project().clone();
                     let weak_workspace = cx.entity().downgrade();
                     workspace.toggle_modal(window, cx, |window, cx| {
@@ -738,7 +738,7 @@ impl FileFinderDelegate {
         self.cancel_flag.store(true, atomic::Ordering::Relaxed);
         self.cancel_flag = Arc::new(AtomicBool::new(false));
         let cancel_flag = self.cancel_flag.clone();
-        cx.spawn_in(window, |picker, mut cx| async move {
+        cx.spawn_in(window, async move |picker, cx| {
             let matches = fuzzy::match_path_sets(
                 candidate_sets.as_slice(),
                 query.path_query(),
@@ -753,7 +753,7 @@ impl FileFinderDelegate {
             .map(ProjectPanelOrdMatch);
             let did_cancel = cancel_flag.load(atomic::Ordering::Relaxed);
             picker
-                .update(&mut cx, |picker, cx| {
+                .update(cx, |picker, cx| {
                     picker
                         .delegate
                         .set_search_matches(search_id, did_cancel, query, matches, cx)
@@ -983,9 +983,9 @@ impl FileFinderDelegate {
         window: &mut Window,
         cx: &mut Context<Picker<Self>>,
     ) -> Task<()> {
-        cx.spawn_in(window, |picker, mut cx| async move {
+        cx.spawn_in(window, async move |picker, cx| {
             let Some(project) = picker
-                .update(&mut cx, |picker, _| picker.delegate.project.clone())
+                .update(cx, |picker, _| picker.delegate.project.clone())
                 .log_err()
             else {
                 return;
@@ -994,7 +994,7 @@ impl FileFinderDelegate {
             let query_path = Path::new(query.path_query());
             let mut path_matches = Vec::new();
 
-            let abs_file_exists = if let Ok(task) = project.update(&mut cx, |this, cx| {
+            let abs_file_exists = if let Ok(task) = project.update(cx, |this, cx| {
                 this.resolve_abs_file_path(query.path_query(), cx)
             }) {
                 task.await.is_some()
@@ -1004,7 +1004,7 @@ impl FileFinderDelegate {
 
             if abs_file_exists {
                 let update_result = project
-                    .update(&mut cx, |project, cx| {
+                    .update(cx, |project, cx| {
                         if let Some((worktree, relative_path)) =
                             project.find_worktree(query_path, cx)
                         {
@@ -1026,7 +1026,7 @@ impl FileFinderDelegate {
             }
 
             picker
-                .update_in(&mut cx, |picker, _, cx| {
+                .update_in(cx, |picker, _, cx| {
                     let picker_delegate = &mut picker.delegate;
                     let search_id = util::post_inc(&mut picker_delegate.search_count);
                     picker_delegate.set_search_matches(search_id, false, query, path_matches, cx);
@@ -1284,13 +1284,13 @@ impl PickerDelegate for FileFinderDelegate {
                     .saturating_sub(1);
                 let finder = self.file_finder.clone();
 
-                cx.spawn_in(window, |_, mut cx| async move {
-                    let item = open_task.await.notify_async_err(&mut cx)?;
+                cx.spawn_in(window, async move |_, cx| {
+                    let item = open_task.await.notify_async_err(cx)?;
                     if let Some(row) = row {
                         if let Some(active_editor) = item.downcast::<Editor>() {
                             active_editor
                                 .downgrade()
-                                .update_in(&mut cx, |editor, window, cx| {
+                                .update_in(cx, |editor, window, cx| {
                                     editor.go_to_singleton_buffer_point(
                                         Point::new(row, col),
                                         window,
@@ -1300,7 +1300,7 @@ impl PickerDelegate for FileFinderDelegate {
                                 .log_err();
                         }
                     }
-                    finder.update(&mut cx, |_, cx| cx.emit(DismissEvent)).ok()?;
+                    finder.update(cx, |_, cx| cx.emit(DismissEvent)).ok()?;
 
                     Some(())
                 })

crates/file_finder/src/new_path_prompt.rs 🔗

@@ -312,7 +312,7 @@ impl PickerDelegate for NewPathDelegate {
         let cancel_flag = self.cancel_flag.clone();
         let query = query.to_string();
         let prefix = dir.clone();
-        cx.spawn_in(window, |picker, mut cx| async move {
+        cx.spawn_in(window, async move |picker, cx| {
             let matches = fuzzy::match_path_sets(
                 candidate_sets.as_slice(),
                 &dir,
@@ -328,7 +328,7 @@ impl PickerDelegate for NewPathDelegate {
                 return;
             }
             picker
-                .update(&mut cx, |picker, cx| {
+                .update(cx, |picker, cx| {
                     picker
                         .delegate
                         .set_search_matches(query, prefix, suffix, matches, cx)
@@ -378,10 +378,10 @@ impl PickerDelegate for NewPathDelegate {
                 &["Replace", "Cancel"],
             cx);
             let m = m.clone();
-            cx.spawn_in(window, |picker, mut cx| async move {
+            cx.spawn_in(window, async move |picker, cx| {
                 let answer = answer.await.ok();
                 picker
-                    .update(&mut cx, |picker, cx| {
+                    .update(cx, |picker, cx| {
                         picker.delegate.should_dismiss = true;
                         if answer != Some(0) {
                             return;

crates/file_finder/src/open_path_prompt.rs 🔗

@@ -161,14 +161,14 @@ impl PickerDelegate for OpenPathDelegate {
         self.cancel_flag = Arc::new(AtomicBool::new(false));
         let cancel_flag = self.cancel_flag.clone();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             if let Some(query) = query {
                 let paths = query.await;
                 if cancel_flag.load(atomic::Ordering::Relaxed) {
                     return;
                 }
 
-                this.update(&mut cx, |this, _| {
+                this.update(cx, |this, _| {
                     this.delegate.directory_state = Some(match paths {
                         Ok(mut paths) => {
                             paths.sort_by(|a, b| compare_paths((&a.path, true), (&b.path, true)));
@@ -201,7 +201,7 @@ impl PickerDelegate for OpenPathDelegate {
             }
 
             let match_candidates = this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     let directory_state = this.delegate.directory_state.as_ref()?;
                     if directory_state.error.is_some() {
                         this.delegate.matches.clear();
@@ -223,7 +223,7 @@ impl PickerDelegate for OpenPathDelegate {
             }
 
             if suffix == "" {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.delegate.matches.clear();
                     this.delegate.string_matches.clear();
                     this.delegate
@@ -250,7 +250,7 @@ impl PickerDelegate for OpenPathDelegate {
                 return;
             }
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.delegate.matches.clear();
                 this.delegate.string_matches = matches.clone();
                 this.delegate

crates/git/src/fake_repository.rs 🔗

@@ -215,7 +215,7 @@ impl GitRepository for FakeGitRepository {
         &self,
         path: RepoPath,
         _content: Rope,
-        _cx: AsyncApp,
+        _cx: &mut AsyncApp,
     ) -> BoxFuture<Result<crate::blame::Blame>> {
         let state = self.state.lock();
         let result = state

crates/git/src/repository.rs 🔗

@@ -207,7 +207,7 @@ pub trait GitRepository: Send + Sync {
         &self,
         path: RepoPath,
         content: Rope,
-        cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> BoxFuture<Result<crate::blame::Blame>>;
 
     /// Returns the absolute path to the repository. For worktrees, this will be the path to the
@@ -678,7 +678,7 @@ impl GitRepository for RealGitRepository {
         &self,
         path: RepoPath,
         content: Rope,
-        cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> BoxFuture<Result<crate::blame::Blame>> {
         let working_directory = self.working_directory();
         let git_binary_path = self.git_binary_path.clone();

crates/git_ui/src/branch_picker.rs 🔗

@@ -90,7 +90,7 @@ impl BranchList {
             .clone()
             .map(|repository| repository.read(cx).branches());
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let mut all_branches = all_branches_request
                 .context("No active repository")?
                 .await??;
@@ -102,7 +102,7 @@ impl BranchList {
                     .map(|commit| 0 - commit.commit_timestamp)
             });
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.picker.update(cx, |picker, cx| {
                     picker.delegate.all_branches = Some(all_branches);
                     picker.refresh(window, cx);
@@ -201,7 +201,7 @@ impl BranchListDelegate {
         let Some(repo) = self.repo.clone() else {
             return;
         };
-        cx.spawn(|_, cx| async move {
+        cx.spawn(async move |_, cx| {
             cx.update(|cx| repo.read(cx).create_branch(new_branch_name.to_string()))?
                 .await??;
             cx.update(|cx| repo.read(cx).change_branch(new_branch_name.to_string()))?
@@ -257,7 +257,7 @@ impl PickerDelegate for BranchListDelegate {
         };
 
         const RECENT_BRANCHES_COUNT: usize = 10;
-        cx.spawn_in(window, move |picker, mut cx| async move {
+        cx.spawn_in(window, async move |picker, cx| {
             let mut matches: Vec<BranchEntry> = if query.is_empty() {
                 all_branches
                     .into_iter()
@@ -293,7 +293,7 @@ impl PickerDelegate for BranchListDelegate {
                 .collect()
             };
             picker
-                .update(&mut cx, |picker, _| {
+                .update(cx, |picker, _| {
                     #[allow(clippy::nonminimal_bool)]
                     if !query.is_empty()
                         && !matches
@@ -350,8 +350,8 @@ impl PickerDelegate for BranchListDelegate {
 
         cx.spawn_in(window, {
             let branch = entry.branch.clone();
-            |picker, mut cx| async move {
-                let branch_change_task = picker.update(&mut cx, |this, cx| {
+            async move |picker, cx| {
+                let branch_change_task = picker.update(cx, |this, cx| {
                     let repo = this
                         .delegate
                         .repo
@@ -369,7 +369,7 @@ impl PickerDelegate for BranchListDelegate {
 
                 branch_change_task.await?;
 
-                picker.update(&mut cx, |_, cx| {
+                picker.update(cx, |_, cx| {
                     cx.emit(DismissEvent);
 
                     anyhow::Ok(())

crates/git_ui/src/git_panel.rs 🔗

@@ -95,7 +95,7 @@ where
     T: IntoEnumIterator + VariantNames + 'static,
 {
     let rx = window.prompt(PromptLevel::Info, msg, detail, &T::VARIANTS, cx);
-    cx.spawn(|_| async move { Ok(T::iter().nth(rx.await?).unwrap()) })
+    cx.spawn(async move |_| Ok(T::iter().nth(rx.await?).unwrap()))
 }
 
 #[derive(strum::EnumIter, strum::VariantNames)]
@@ -268,14 +268,14 @@ impl ScrollbarProperties {
         }
 
         let axis = self.axis;
-        self.hide_task = Some(cx.spawn_in(window, |panel, mut cx| async move {
+        self.hide_task = Some(cx.spawn_in(window, async move |panel, cx| {
             cx.background_executor()
                 .timer(SCROLLBAR_SHOW_INTERVAL)
                 .await;
 
             if let Some(panel) = panel.upgrade() {
                 panel
-                    .update(&mut cx, |panel, cx| {
+                    .update(cx, |panel, cx| {
                         match axis {
                             Axis::Vertical => panel.vertical_scrollbar.show_scrollbar = false,
                             Axis::Horizontal => panel.horizontal_scrollbar.show_scrollbar = false,
@@ -969,12 +969,12 @@ impl GitPanel {
                 self.perform_checkout(vec![entry.clone()], cx);
             } else {
                 let prompt = prompt(&format!("Trash {}?", filename), None, window, cx);
-                cx.spawn_in(window, |_, mut cx| async move {
+                cx.spawn_in(window, async move |_, cx| {
                     match prompt.await? {
                         TrashCancel::Trash => {}
                         TrashCancel::Cancel => return Ok(()),
                     }
-                    let task = workspace.update(&mut cx, |workspace, cx| {
+                    let task = workspace.update(cx, |workspace, cx| {
                         workspace
                             .project()
                             .update(cx, |project, cx| project.delete_file(path, true, cx))
@@ -1009,8 +1009,8 @@ impl GitPanel {
             finished: false,
         });
         self.update_visible_entries(cx);
-        let task = cx.spawn(|_, mut cx| async move {
-            let tasks: Vec<_> = workspace.update(&mut cx, |workspace, cx| {
+        let task = cx.spawn(async move |_, cx| {
+            let tasks: Vec<_> = workspace.update(cx, |workspace, cx| {
                 workspace.project().update(cx, |project, cx| {
                     entries
                         .iter()
@@ -1027,7 +1027,7 @@ impl GitPanel {
             let buffers = futures::future::join_all(tasks).await;
 
             active_repository
-                .update(&mut cx, |repo, cx| {
+                .update(cx, |repo, cx| {
                     repo.checkout_files(
                         "HEAD",
                         entries
@@ -1055,10 +1055,10 @@ impl GitPanel {
             Ok(())
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = task.await;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 for pending in this.pending.iter_mut() {
                     if pending.op_id == op_id {
                         pending.finished = true;
@@ -1120,17 +1120,15 @@ impl GitPanel {
             window,
             cx,
         );
-        cx.spawn(|this, mut cx| async move {
-            match prompt.await {
-                Ok(RestoreCancel::RestoreTrackedFiles) => {
-                    this.update(&mut cx, |this, cx| {
-                        this.perform_checkout(entries, cx);
-                    })
-                    .ok();
-                }
-                _ => {
-                    return;
-                }
+        cx.spawn(async move |this, cx| match prompt.await {
+            Ok(RestoreCancel::RestoreTrackedFiles) => {
+                this.update(cx, |this, cx| {
+                    this.perform_checkout(entries, cx);
+                })
+                .ok();
+            }
+            _ => {
+                return;
             }
         })
         .detach();
@@ -1173,12 +1171,12 @@ impl GitPanel {
         }
 
         let prompt = prompt("Trash these files?", Some(&details), window, cx);
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             match prompt.await? {
                 TrashCancel::Trash => {}
                 TrashCancel::Cancel => return Ok(()),
             }
-            let tasks = workspace.update(&mut cx, |workspace, cx| {
+            let tasks = workspace.update(cx, |workspace, cx| {
                 to_delete
                     .iter()
                     .filter_map(|entry| {
@@ -1195,9 +1193,7 @@ impl GitPanel {
                 .into_iter()
                 .filter(|entry| !entry.status.staging().is_fully_unstaged())
                 .collect();
-            this.update(&mut cx, |this, cx| {
-                this.change_file_stage(false, to_unstage, cx)
-            })?;
+            this.update(cx, |this, cx| this.change_file_stage(false, to_unstage, cx))?;
             for task in tasks {
                 task.await?;
             }
@@ -1292,7 +1288,7 @@ impl GitPanel {
         cx.notify();
 
         cx.spawn({
-            |this, mut cx| async move {
+            async move |this, cx| {
                 let result = cx
                     .update(|cx| {
                         if stage {
@@ -1315,7 +1311,7 @@ impl GitPanel {
                     })?
                     .await;
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     for pending in this.pending.iter_mut() {
                         if pending.op_id == op_id {
                             pending.finished = true
@@ -1417,7 +1413,7 @@ impl GitPanel {
         };
         let error_spawn = |message, window: &mut Window, cx: &mut App| {
             let prompt = window.prompt(PromptLevel::Warning, message, None, &["Ok"], cx);
-            cx.spawn(|_| async move {
+            cx.spawn(async move |_| {
                 prompt.await.ok();
             })
             .detach();
@@ -1464,16 +1460,16 @@ impl GitPanel {
 
             let stage_task =
                 active_repository.update(cx, |repo, cx| repo.stage_entries(changed_files, cx));
-            cx.spawn(|_, mut cx| async move {
+            cx.spawn(async move |_, cx| {
                 stage_task.await?;
                 let commit_task = active_repository
-                    .update(&mut cx, |repo, cx| repo.commit(message.into(), None, cx))?;
+                    .update(cx, |repo, cx| repo.commit(message.into(), None, cx))?;
                 commit_task.await?
             })
         };
-        let task = cx.spawn_in(window, |this, mut cx| async move {
+        let task = cx.spawn_in(window, async move |this, cx| {
             let result = task.await;
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.pending_commit.take();
                 match result {
                     Ok(()) => {
@@ -1498,12 +1494,12 @@ impl GitPanel {
         let confirmation = self.check_for_pushed_commits(window, cx);
         let prior_head = self.load_commit_details("HEAD".to_string(), cx);
 
-        let task = cx.spawn_in(window, |this, mut cx| async move {
+        let task = cx.spawn_in(window, async move |this, cx| {
             let result = maybe!(async {
                 if let Ok(true) = confirmation.await {
                     let prior_head = prior_head.await?;
 
-                    repo.update(&mut cx, |repo, cx| {
+                    repo.update(cx, |repo, cx| {
                         repo.reset("HEAD^".to_string(), ResetMode::Soft, cx)
                     })?
                     .await??;
@@ -1515,7 +1511,7 @@ impl GitPanel {
             })
             .await;
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.pending_commit.take();
                 match result {
                     Ok(None) => {}
@@ -1646,17 +1642,10 @@ impl GitPanel {
             }
         });
 
-        self.generate_commit_message_task = Some(cx.spawn(|this, mut cx| {
-            async move {
-                let _defer = util::defer({
-                    let mut cx = cx.clone();
-                    let this = this.clone();
-                    move || {
-                        this.update(&mut cx, |this, _cx| {
-                            this.generate_commit_message_task.take();
-                        })
-                        .ok();
-                    }
+        self.generate_commit_message_task = Some(cx.spawn(async move |this, cx| {
+             async move {
+                let _defer = cx.on_drop(&this, |this, _cx| {
+                    this.generate_commit_message_task.take();
                 });
 
                 let mut diff_text = diff.await??;
@@ -1666,7 +1655,7 @@ impl GitPanel {
                     diff_text = diff_text.chars().take(ONE_MB).collect()
                 }
 
-                let subject = this.update(&mut cx, |this, cx| {
+                let subject = this.update(cx, |this, cx| {
                     this.commit_editor.read(cx).text(cx).lines().next().map(ToOwned::to_owned).unwrap_or_default()
                 })?;
 
@@ -1695,7 +1684,7 @@ impl GitPanel {
                 let mut messages = stream.await?;
 
                 if !text_empty {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.commit_message_buffer(cx).update(cx, |buffer, cx| {
                             let insert_position = buffer.anchor_before(buffer.len());
                             buffer.edit([(insert_position..insert_position, "\n")], None, cx)
@@ -1706,7 +1695,7 @@ impl GitPanel {
                 while let Some(message) = messages.stream.next().await {
                     let text = message?;
 
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.commit_message_buffer(cx).update(cx, |buffer, cx| {
                             let insert_position = buffer.anchor_before(buffer.len());
                             buffer.edit([(insert_position..insert_position, text)], None, cx);
@@ -1716,7 +1705,7 @@ impl GitPanel {
 
                 anyhow::Ok(())
             }
-            .log_err()
+            .log_err().await
         }));
     }
 
@@ -1733,12 +1722,12 @@ impl GitPanel {
         let askpass = self.askpass_delegate("git fetch", window, cx);
         let this = cx.weak_entity();
         window
-            .spawn(cx, |mut cx| async move {
-                let fetch = repo.update(&mut cx, |repo, cx| repo.fetch(askpass, cx))?;
+            .spawn(cx, async move |cx| {
+                let fetch = repo.update(cx, |repo, cx| repo.fetch(askpass, cx))?;
 
                 let remote_message = fetch.await?;
                 drop(guard);
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     let action = RemoteAction::Fetch;
                     match remote_message {
                         Ok(remote_message) => this.show_remote_output(action, remote_message, cx),
@@ -1803,10 +1792,10 @@ impl GitPanel {
                 cx,
             );
 
-            cx.spawn(|_, _| async move { prompt.await.map(|ix| worktrees[ix].clone()) })
+            cx.spawn(async move |_, _| prompt.await.map(|ix| worktrees[ix].clone()))
         };
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let worktree = match worktree.await {
                 Some(worktree) => worktree,
                 None => {
@@ -1814,7 +1803,7 @@ impl GitPanel {
                 }
             };
 
-            let Ok(result) = this.update(&mut cx, |this, cx| {
+            let Ok(result) = this.update(cx, |this, cx| {
                 let fallback_branch_name = GitPanelSettings::get_global(cx)
                     .fallback_branch_name
                     .clone();
@@ -1829,7 +1818,7 @@ impl GitPanel {
 
             let result = result.await;
 
-            this.update_in(&mut cx, |this, _, cx| match result {
+            this.update_in(cx, |this, _, cx| match result {
                 Ok(()) => {}
                 Err(e) => this.show_error_toast("init", e, cx),
             })
@@ -1851,7 +1840,7 @@ impl GitPanel {
         telemetry::event!("Git Pulled");
         let branch = branch.clone();
         let remote = self.get_current_remote(window, cx);
-        cx.spawn_in(window, move |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let remote = match remote.await {
                 Ok(Some(remote)) => remote,
                 Ok(None) => {
@@ -1859,21 +1848,21 @@ impl GitPanel {
                 }
                 Err(e) => {
                     log::error!("Failed to get current remote: {}", e);
-                    this.update(&mut cx, |this, cx| this.show_error_toast("pull", e, cx))
+                    this.update(cx, |this, cx| this.show_error_toast("pull", e, cx))
                         .ok();
                     return Ok(());
                 }
             };
 
-            let askpass = this.update_in(&mut cx, |this, window, cx| {
+            let askpass = this.update_in(cx, |this, window, cx| {
                 this.askpass_delegate(format!("git pull {}", remote.name), window, cx)
             })?;
 
             let guard = this
-                .update(&mut cx, |this, _| this.start_remote_operation())
+                .update(cx, |this, _| this.start_remote_operation())
                 .ok();
 
-            let pull = repo.update(&mut cx, |repo, cx| {
+            let pull = repo.update(cx, |repo, cx| {
                 repo.pull(branch.name.clone(), remote.name.clone(), askpass, cx)
             })?;
 
@@ -1881,7 +1870,7 @@ impl GitPanel {
             drop(guard);
 
             let action = RemoteAction::Pull(remote);
-            this.update(&mut cx, |this, cx| match remote_message {
+            this.update(cx, |this, cx| match remote_message {
                 Ok(remote_message) => this.show_remote_output(action, remote_message, cx),
                 Err(e) => {
                     log::error!("Error while pulling {:?}", e);
@@ -1922,7 +1911,7 @@ impl GitPanel {
         };
         let remote = self.get_current_remote(window, cx);
 
-        cx.spawn_in(window, move |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let remote = match remote.await {
                 Ok(Some(remote)) => remote,
                 Ok(None) => {
@@ -1930,21 +1919,21 @@ impl GitPanel {
                 }
                 Err(e) => {
                     log::error!("Failed to get current remote: {}", e);
-                    this.update(&mut cx, |this, cx| this.show_error_toast("push", e, cx))
+                    this.update(cx, |this, cx| this.show_error_toast("push", e, cx))
                         .ok();
                     return Ok(());
                 }
             };
 
-            let askpass_delegate = this.update_in(&mut cx, |this, window, cx| {
+            let askpass_delegate = this.update_in(cx, |this, window, cx| {
                 this.askpass_delegate(format!("git push {}", remote.name), window, cx)
             })?;
 
             let guard = this
-                .update(&mut cx, |this, _| this.start_remote_operation())
+                .update(cx, |this, _| this.start_remote_operation())
                 .ok();
 
-            let push = repo.update(&mut cx, |repo, cx| {
+            let push = repo.update(cx, |repo, cx| {
                 repo.push(
                     branch.name.clone(),
                     remote.name.clone(),
@@ -1958,7 +1947,7 @@ impl GitPanel {
             drop(guard);
 
             let action = RemoteAction::Push(branch.name, remote);
-            this.update(&mut cx, |this, cx| match remote_output {
+            this.update(cx, |this, cx| match remote_output {
                 Ok(remote_message) => this.show_remote_output(action, remote_message, cx),
                 Err(e) => {
                     log::error!("Error while pushing {:?}", e);
@@ -2167,11 +2156,11 @@ impl GitPanel {
     ) {
         let handle = cx.entity().downgrade();
         self.reopen_commit_buffer(window, cx);
-        self.update_visible_entries_task = cx.spawn_in(window, |_, mut cx| async move {
+        self.update_visible_entries_task = cx.spawn_in(window, async move |_, cx| {
             cx.background_executor().timer(UPDATE_DEBOUNCE).await;
             if let Some(git_panel) = handle.upgrade() {
                 git_panel
-                    .update_in(&mut cx, |git_panel, window, cx| {
+                    .update_in(cx, |git_panel, window, cx| {
                         if clear_pending {
                             git_panel.clear_pending();
                         }
@@ -2196,9 +2185,9 @@ impl GitPanel {
             )
         });
 
-        cx.spawn_in(window, |git_panel, mut cx| async move {
+        cx.spawn_in(window, async move |git_panel, cx| {
             let buffer = load_buffer.await?;
-            git_panel.update_in(&mut cx, |git_panel, window, cx| {
+            git_panel.update_in(cx, |git_panel, window, cx| {
                 if git_panel
                     .commit_editor
                     .read(cx)
@@ -3449,7 +3438,7 @@ impl GitPanel {
         };
         repo.update(cx, |repo, cx| {
             let show = repo.show(sha);
-            cx.spawn(|_, _| async move { show.await? })
+            cx.spawn(async move |_, _| show.await?)
         })
     }
 
@@ -3948,9 +3937,9 @@ impl GitPanelMessageTooltip {
         cx: &mut App,
     ) -> Entity<Self> {
         cx.new(|cx| {
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 let details = git_panel
-                    .update(&mut cx, |git_panel, cx| {
+                    .update(cx, |git_panel, cx| {
                         git_panel.load_commit_details(sha.to_string(), cx)
                     })?
                     .await?;
@@ -3966,7 +3955,7 @@ impl GitPanelMessageTooltip {
                     }),
                 };
 
-                this.update_in(&mut cx, |this: &mut GitPanelMessageTooltip, window, cx| {
+                this.update_in(cx, |this: &mut GitPanelMessageTooltip, window, cx| {
                     this.commit_tooltip =
                         Some(cx.new(move |cx| CommitTooltip::new(commit_details, window, cx)));
                     cx.notify();

crates/git_ui/src/onboarding.rs 🔗

@@ -184,9 +184,11 @@ fn get_dismissed() -> bool {
 }
 
 fn persist_dismissed(cx: &mut App) {
-    cx.spawn(|_| {
+    cx.spawn(async |_| {
         let time = chrono::Utc::now().to_rfc3339();
-        db::kvp::KEY_VALUE_STORE.write_kvp(DISMISSED_AT_KEY.into(), time)
+        db::kvp::KEY_VALUE_STORE
+            .write_kvp(DISMISSED_AT_KEY.into(), time)
+            .await
     })
     .detach_and_log_err(cx);
 }
@@ -202,8 +204,12 @@ pub(crate) fn clear_dismissed(cx: &mut App) {
             });
     });
 
-    cx.spawn(|_| db::kvp::KEY_VALUE_STORE.delete_kvp(DISMISSED_AT_KEY.into()))
-        .detach_and_log_err(cx);
+    cx.spawn(async |_| {
+        db::kvp::KEY_VALUE_STORE
+            .delete_kvp(DISMISSED_AT_KEY.into())
+            .await
+    })
+    .detach_and_log_err(cx);
 }
 
 impl Render for GitBanner {

crates/git_ui/src/picker_prompt.rs 🔗

@@ -31,13 +31,13 @@ pub fn prompt(
     }
     let prompt = prompt.to_string().into();
 
-    window.spawn(cx, |mut cx| async move {
+    window.spawn(cx, async move |cx| {
         // Modal branch picker has a longer trailoff than a popover one.
         let (tx, rx) = oneshot::channel();
         let delegate = PickerPromptDelegate::new(prompt, options, tx, 70);
 
         workspace
-            .update_in(&mut cx, |workspace, window, cx| {
+            .update_in(cx, |workspace, window, cx| {
                 workspace.toggle_modal(window, cx, |window, cx| {
                     PickerPrompt::new(delegate, 34., window, cx)
                 })
@@ -146,8 +146,8 @@ impl PickerDelegate for PickerPromptDelegate {
         window: &mut Window,
         cx: &mut Context<Picker<Self>>,
     ) -> Task<()> {
-        cx.spawn_in(window, move |picker, mut cx| async move {
-            let candidates = picker.update(&mut cx, |picker, _| {
+        cx.spawn_in(window, async move |picker, cx| {
+            let candidates = picker.update(cx, |picker, _| {
                 picker
                     .delegate
                     .all_options
@@ -182,7 +182,7 @@ impl PickerDelegate for PickerPromptDelegate {
                 .await
             };
             picker
-                .update(&mut cx, |picker, _| {
+                .update(cx, |picker, _| {
                     let delegate = &mut picker.delegate;
                     delegate.matches = matches;
                     if delegate.matches.is_empty() {

crates/git_ui/src/project_diff.rs 🔗

@@ -165,7 +165,7 @@ impl ProjectDiff {
         let (mut send, recv) = postage::watch::channel::<()>();
         let worker = window.spawn(cx, {
             let this = cx.weak_entity();
-            |cx| Self::handle_status_updates(this, recv, cx)
+            async |cx| Self::handle_status_updates(this, recv, cx).await
         });
         // Kick off a refresh immediately
         *send.borrow_mut() = ();
@@ -361,10 +361,10 @@ impl ProjectDiff {
                     .update(cx, |project, cx| project.open_buffer(project_path, cx));
 
                 let project = self.project.clone();
-                result.push(cx.spawn(|_, mut cx| async move {
+                result.push(cx.spawn(async move |_, cx| {
                     let buffer = load_buffer.await?;
                     let changes = project
-                        .update(&mut cx, |project, cx| {
+                        .update(cx, |project, cx| {
                             project.open_uncommitted_diff(buffer.clone(), cx)
                         })?
                         .await?;
@@ -447,10 +447,10 @@ impl ProjectDiff {
     pub async fn handle_status_updates(
         this: WeakEntity<Self>,
         mut recv: postage::watch::Receiver<()>,
-        mut cx: AsyncWindowContext,
+        cx: &mut AsyncWindowContext,
     ) -> Result<()> {
         while let Some(_) = recv.next().await {
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let new_branch =
                     this.git_store
                         .read(cx)
@@ -464,7 +464,7 @@ impl ProjectDiff {
                 }
             })?;
 
-            let buffers_to_load = this.update(&mut cx, |this, cx| this.load_buffers(cx))?;
+            let buffers_to_load = this.update(cx, |this, cx| this.load_buffers(cx))?;
             for buffer_to_load in buffers_to_load {
                 if let Some(buffer) = buffer_to_load.await.log_err() {
                     cx.update(|window, cx| {
@@ -473,7 +473,7 @@ impl ProjectDiff {
                     })?;
                 }
             }
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.pending_scroll.take();
                 cx.notify();
             })?;
@@ -750,8 +750,8 @@ impl SerializableItem for ProjectDiff {
         window: &mut Window,
         cx: &mut App,
     ) -> Task<Result<Entity<Self>>> {
-        window.spawn(cx, |mut cx| async move {
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+        window.spawn(cx, async move |cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 let workspace_handle = cx.entity();
                 cx.new(|cx| Self::new(workspace.project().clone(), workspace_handle, window, cx))
             })

crates/git_ui/src/repository_selector.rs 🔗

@@ -167,7 +167,7 @@ impl PickerDelegate for RepositorySelectorDelegate {
     ) -> Task<()> {
         let all_repositories = self.repository_entries.clone();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let filtered_repositories = cx
                 .background_spawn(async move {
                     if query.is_empty() {
@@ -184,7 +184,7 @@ impl PickerDelegate for RepositorySelectorDelegate {
                 })
                 .await;
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.delegate.filtered_repositories = filtered_repositories;
                 this.delegate.set_selected_index(0, window, cx);
                 cx.notify();

crates/go_to_line/src/cursor_position.rs 🔗

@@ -72,11 +72,9 @@ impl CursorPosition {
         cx: &mut Context<Self>,
     ) {
         let editor = editor.downgrade();
-        self.update_position = cx.spawn_in(window, |cursor_position, mut cx| async move {
+        self.update_position = cx.spawn_in(window, async move |cursor_position, cx| {
             let is_singleton = editor
-                .update(&mut cx, |editor, cx| {
-                    editor.buffer().read(cx).is_singleton()
-                })
+                .update(cx, |editor, cx| editor.buffer().read(cx).is_singleton())
                 .ok()
                 .unwrap_or(true);
 
@@ -87,7 +85,7 @@ impl CursorPosition {
             }
 
             editor
-                .update(&mut cx, |editor, cx| {
+                .update(cx, |editor, cx| {
                     cursor_position.update(cx, |cursor_position, cx| {
                         cursor_position.selected_count = SelectionStats::default();
                         cursor_position.selected_count.selections = editor.selections.count();

crates/gpui/examples/opacity.rs 🔗

@@ -50,25 +50,23 @@ impl HelloWorld {
         self.opacity = 0.0;
         cx.notify();
 
-        self._task = Some(cx.spawn_in(window, |view, mut cx| async move {
-            loop {
-                Timer::after(Duration::from_secs_f32(0.05)).await;
-                let mut stop = false;
-                let _ = cx.update(|_, cx| {
-                    view.update(cx, |view, cx| {
-                        if view.opacity >= 1.0 {
-                            stop = true;
-                            return;
-                        }
+        self._task = Some(cx.spawn_in(window, async move |view, cx| loop {
+            Timer::after(Duration::from_secs_f32(0.05)).await;
+            let mut stop = false;
+            let _ = cx.update(|_, cx| {
+                view.update(cx, |view, cx| {
+                    if view.opacity >= 1.0 {
+                        stop = true;
+                        return;
+                    }
 
-                        view.opacity += 0.1;
-                        cx.notify();
-                    })
-                });
+                    view.opacity += 0.1;
+                    cx.notify();
+                })
+            });
 
-                if stop {
-                    break;
-                }
+            if stop {
+                break;
             }
         }));
     }

crates/gpui/examples/window.rs 🔗

@@ -157,7 +157,7 @@ impl Render for WindowDemo {
 
                 // Restore the application after 3 seconds
                 window
-                    .spawn(cx, |mut cx| async move {
+                    .spawn(cx, async move |cx| {
                         Timer::after(std::time::Duration::from_secs(3)).await;
                         cx.update(|_, cx| {
                             cx.activate(false);

crates/gpui/src/app.rs 🔗

@@ -1049,12 +1049,14 @@ impl App {
     /// Spawns the future returned by the given function on the main thread. The closure will be invoked
     /// with [AsyncApp], which allows the application state to be accessed across await points.
     #[track_caller]
-    pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncApp) -> Fut) -> Task<R>
+    pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
     where
-        Fut: Future<Output = R> + 'static,
+        AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
         R: 'static,
     {
-        self.foreground_executor.spawn(f(self.to_async()))
+        let mut cx = self.to_async();
+        self.foreground_executor
+            .spawn(async move { f(&mut cx).await })
     }
 
     /// Schedules the given function to be run at the end of the current effect cycle, allowing entities

crates/gpui/src/app/async_context.rs 🔗

@@ -8,7 +8,7 @@ use derive_more::{Deref, DerefMut};
 use futures::channel::oneshot;
 use std::{future::Future, rc::Weak};
 
-use super::Context;
+use super::{Context, WeakEntity};
 
 /// An async-friendly version of [App] with a static lifetime so it can be held across `await` points in async code.
 /// You're provided with an instance when calling [App::spawn], and you can also create one with [App::to_async].
@@ -173,12 +173,14 @@ impl AsyncApp {
 
     /// Schedule a future to be polled in the background.
     #[track_caller]
-    pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncApp) -> Fut) -> Task<R>
+    pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
     where
-        Fut: Future<Output = R> + 'static,
+        AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
         R: 'static,
     {
-        self.foreground_executor.spawn(f(self.clone()))
+        let mut cx = self.clone();
+        self.foreground_executor
+            .spawn(async move { f(&mut cx).await })
     }
 
     /// Determine whether global state of the specified type has been assigned.
@@ -230,6 +232,19 @@ impl AsyncApp {
         let mut app = app.borrow_mut();
         Ok(app.update(|cx| cx.update_global(update)))
     }
+
+    /// Run something using this entity and cx, when the returned struct is dropped
+    pub fn on_drop<T: 'static>(
+        &self,
+        entity: &WeakEntity<T>,
+        f: impl FnOnce(&mut T, &mut Context<T>) + 'static,
+    ) -> util::Deferred<impl FnOnce()> {
+        let entity = entity.clone();
+        let mut cx = self.clone();
+        util::defer(move || {
+            entity.update(&mut cx, f).ok();
+        })
+    }
 }
 
 /// A cloneable, owned handle to the application context,
@@ -299,12 +314,14 @@ impl AsyncWindowContext {
     /// Schedule a future to be executed on the main thread. This is used for collecting
     /// the results of background tasks and updating the UI.
     #[track_caller]
-    pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncWindowContext) -> Fut) -> Task<R>
+    pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
     where
-        Fut: Future<Output = R> + 'static,
+        AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
         R: 'static,
     {
-        self.foreground_executor.spawn(f(self.clone()))
+        let mut cx = self.clone();
+        self.foreground_executor
+            .spawn(async move { f(&mut cx).await })
     }
 
     /// Present a platform dialog.

crates/gpui/src/app/context.rs 🔗

@@ -12,6 +12,7 @@ use std::{
     future::Future,
     sync::Arc,
 };
+use util::Deferred;
 
 use super::{App, AsyncWindowContext, Entity, KeystrokeEvent};
 
@@ -199,14 +200,14 @@ impl<'a, T: 'static> Context<'a, T> {
     /// The function is provided a weak handle to the entity owned by this context and a context that can be held across await points.
     /// The returned task must be held or detached.
     #[track_caller]
-    pub fn spawn<Fut, R>(&self, f: impl FnOnce(WeakEntity<T>, AsyncApp) -> Fut) -> Task<R>
+    pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
     where
         T: 'static,
-        Fut: Future<Output = R> + 'static,
+        AsyncFn: AsyncFnOnce(WeakEntity<T>, &mut AsyncApp) -> R + 'static,
         R: 'static,
     {
         let this = self.weak_entity();
-        self.app.spawn(|cx| f(this, cx))
+        self.app.spawn(async move |cx| f(this, cx).await)
     }
 
     /// Convenience method for accessing view state in an event callback.
@@ -224,6 +225,18 @@ impl<'a, T: 'static> Context<'a, T> {
         }
     }
 
+    /// Run something using this entity and cx, when the returned struct is dropped
+    pub fn on_drop(
+        &self,
+        f: impl FnOnce(&mut T, &mut Context<T>) + 'static,
+    ) -> Deferred<impl FnOnce()> {
+        let this = self.weak_entity();
+        let mut cx = self.to_async();
+        util::defer(move || {
+            this.update(&mut cx, f).ok();
+        })
+    }
+
     /// Focus the given view in the given window. View type is required to implement Focusable.
     pub fn focus_view<W: Focusable>(&mut self, view: &Entity<W>, window: &mut Window) {
         window.focus(&view.focus_handle(self));
@@ -600,17 +613,13 @@ impl<'a, T: 'static> Context<'a, T> {
     /// It's also given an [`AsyncWindowContext`], which can be used to access the state of the view across await points.
     /// The returned future will be polled on the main thread.
     #[track_caller]
-    pub fn spawn_in<Fut, R>(
-        &self,
-        window: &Window,
-        f: impl FnOnce(WeakEntity<T>, AsyncWindowContext) -> Fut,
-    ) -> Task<R>
+    pub fn spawn_in<AsyncFn, R>(&self, window: &Window, f: AsyncFn) -> Task<R>
     where
         R: 'static,
-        Fut: Future<Output = R> + 'static,
+        AsyncFn: AsyncFnOnce(WeakEntity<T>, &mut AsyncWindowContext) -> R + 'static,
     {
         let view = self.weak_entity();
-        window.spawn(self, |mut cx| f(view, cx))
+        window.spawn(self, async move |cx| f(view, cx).await)
     }
 
     /// Register a callback to be invoked when the given global state changes.

crates/gpui/src/elements/div.rs 🔗

@@ -2485,7 +2485,7 @@ fn handle_tooltip_mouse_move(
                 let active_tooltip = active_tooltip.clone();
                 let build_tooltip = build_tooltip.clone();
                 let check_is_hovered_during_prepaint = check_is_hovered_during_prepaint.clone();
-                move |mut cx| async move {
+                async move |cx| {
                     cx.background_executor().timer(TOOLTIP_SHOW_DELAY).await;
                     cx.update(|window, cx| {
                         let new_tooltip =
@@ -2576,7 +2576,7 @@ fn handle_tooltip_check_visible_and_update(
         Action::ScheduleHide(tooltip) => {
             let delayed_hide_task = window.spawn(cx, {
                 let active_tooltip = active_tooltip.clone();
-                move |mut cx| async move {
+                async move |cx| {
                     cx.background_executor()
                         .timer(HOVERABLE_TOOLTIP_HIDE_DELAY)
                         .await;

crates/gpui/src/elements/img.rs 🔗

@@ -357,7 +357,7 @@ impl Element for Img {
                                     }
                                 } else {
                                     let current_view = window.current_view();
-                                    let task = window.spawn(cx, |mut cx| async move {
+                                    let task = window.spawn(cx, async move |cx| {
                                         cx.background_executor().timer(LOADING_DELAY).await;
                                         cx.update(move |_, cx| {
                                             cx.notify(current_view);

crates/gpui/src/window.rs 🔗

@@ -33,7 +33,6 @@ use std::{
     cell::{Cell, RefCell},
     cmp,
     fmt::{Debug, Display},
-    future::Future,
     hash::{Hash, Hasher},
     marker::PhantomData,
     mem,
@@ -1292,12 +1291,16 @@ impl Window {
     /// The closure is provided a handle to the current window and an `AsyncWindowContext` for
     /// use within your future.
     #[track_caller]
-    pub fn spawn<Fut, R>(&self, cx: &App, f: impl FnOnce(AsyncWindowContext) -> Fut) -> Task<R>
+    pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
     where
         R: 'static,
-        Fut: Future<Output = R> + 'static,
+        AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
     {
-        cx.spawn(|app| f(AsyncWindowContext::new_context(app, self.handle)))
+        let handle = self.handle;
+        cx.spawn(async move |app| {
+            let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
+            f(&mut async_window_cx).await
+        })
     }
 
     fn bounds_changed(&mut self, cx: &mut App) {
@@ -2068,7 +2071,7 @@ impl Window {
                 let entity = self.current_view();
                 self.spawn(cx, {
                     let task = task.clone();
-                    |mut cx| async move {
+                    async move |cx| {
                         task.await;
 
                         cx.on_next_frame(move |_, cx| {
@@ -3241,7 +3244,7 @@ impl Window {
         if !match_result.pending.is_empty() {
             currently_pending.keystrokes = match_result.pending;
             currently_pending.focus = self.focus;
-            currently_pending.timer = Some(self.spawn(cx, |mut cx| async move {
+            currently_pending.timer = Some(self.spawn(cx, async move |cx| {
                 cx.background_executor.timer(Duration::from_secs(1)).await;
                 cx.update(move |window, cx| {
                     let Some(currently_pending) = window

crates/image_viewer/src/image_viewer.rs 🔗

@@ -209,18 +209,18 @@ impl SerializableItem for ImageView {
         window: &mut Window,
         cx: &mut App,
     ) -> Task<gpui::Result<Entity<Self>>> {
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let image_path = IMAGE_VIEWER
                 .get_image_path(item_id, workspace_id)?
                 .ok_or_else(|| anyhow::anyhow!("No image path found"))?;
 
             let (worktree, relative_path) = project
-                .update(&mut cx, |project, cx| {
+                .update(cx, |project, cx| {
                     project.find_or_create_worktree(image_path.clone(), false, cx)
                 })?
                 .await
                 .context("Path not found")?;
-            let worktree_id = worktree.update(&mut cx, |worktree, _cx| worktree.id())?;
+            let worktree_id = worktree.update(cx, |worktree, _cx| worktree.id())?;
 
             let project_path = ProjectPath {
                 worktree_id,
@@ -228,7 +228,7 @@ impl SerializableItem for ImageView {
             };
 
             let image_item = project
-                .update(&mut cx, |project, cx| project.open_image(project_path, cx))?
+                .update(cx, |project, cx| project.open_image(project_path, cx))?
                 .await?;
 
             cx.update(|_, cx| Ok(cx.new(|cx| ImageView::new(image_item, project, cx))))?
@@ -241,8 +241,10 @@ impl SerializableItem for ImageView {
         window: &mut Window,
         cx: &mut App,
     ) -> Task<gpui::Result<()>> {
-        window.spawn(cx, |_| {
-            IMAGE_VIEWER.delete_unloaded_items(workspace_id, alive_items)
+        window.spawn(cx, async move |_| {
+            IMAGE_VIEWER
+                .delete_unloaded_items(workspace_id, alive_items)
+                .await
         })
     }
 

crates/inline_completion_button/src/inline_completion_button.rs 🔗

@@ -604,11 +604,11 @@ impl InlineCompletionButton {
                     if let Some(workspace) = window.root().flatten() {
                         let workspace = workspace.downgrade();
                         window
-                            .spawn(cx, |cx| {
+                            .spawn(cx, async |cx| {
                                 open_disabled_globs_setting_in_editor(
                                     workspace,
                                     cx,
-                                )
+                                ).await
                             })
                             .detach_and_log_err(cx);
                     }
@@ -768,10 +768,10 @@ impl SupermavenButtonStatus {
 
 async fn open_disabled_globs_setting_in_editor(
     workspace: WeakEntity<Workspace>,
-    mut cx: AsyncWindowContext,
+    cx: &mut AsyncWindowContext,
 ) -> Result<()> {
     let settings_editor = workspace
-        .update_in(&mut cx, |_, window, cx| {
+        .update_in(cx, |_, window, cx| {
             create_and_open_local_file(paths::settings_file(), window, cx, || {
                 settings::initial_user_settings_content().as_ref().into()
             })
@@ -782,7 +782,7 @@ async fn open_disabled_globs_setting_in_editor(
 
     settings_editor
         .downgrade()
-        .update_in(&mut cx, |item, window, cx| {
+        .update_in(cx, |item, window, cx| {
             let text = item.buffer().read(cx).snapshot(cx).text();
 
             let settings = cx.global::<SettingsStore>();

crates/journal/src/journal.rs 🔗

@@ -118,7 +118,7 @@ pub fn new_journal_entry(workspace: &Workspace, window: &mut Window, cx: &mut Ap
     let view_snapshot = workspace.weak_handle().clone();
 
     window
-        .spawn(cx, |mut cx| async move {
+        .spawn(cx, async move |cx| {
             let (journal_dir, entry_path) = create_entry.await?;
             let opened = if open_new_workspace {
                 let (new_workspace, _) = cx
@@ -132,7 +132,7 @@ pub fn new_journal_entry(workspace: &Workspace, window: &mut Window, cx: &mut Ap
                     })?
                     .await?;
                 new_workspace
-                    .update(&mut cx, |workspace, window, cx| {
+                    .update(cx, |workspace, window, cx| {
                         workspace.open_paths(
                             vec![entry_path],
                             workspace::OpenOptions {
@@ -147,7 +147,7 @@ pub fn new_journal_entry(workspace: &Workspace, window: &mut Window, cx: &mut Ap
                     .await
             } else {
                 view_snapshot
-                    .update_in(&mut cx, |workspace, window, cx| {
+                    .update_in(cx, |workspace, window, cx| {
                         workspace.open_paths(
                             vec![entry_path],
                             workspace::OpenOptions {
@@ -164,7 +164,7 @@ pub fn new_journal_entry(workspace: &Workspace, window: &mut Window, cx: &mut Ap
 
             if let Some(Some(Ok(item))) = opened.first() {
                 if let Some(editor) = item.downcast::<Editor>().map(|editor| editor.downgrade()) {
-                    editor.update_in(&mut cx, |editor, window, cx| {
+                    editor.update_in(cx, |editor, window, cx| {
                         let len = editor.buffer().read(cx).len(cx);
                         editor.change_selections(Some(Autoscroll::center()), window, cx, |s| {
                             s.select_ranges([len..len])

crates/language/src/buffer.rs 🔗

@@ -1304,8 +1304,8 @@ impl Buffer {
     pub fn reload(&mut self, cx: &Context<Self>) -> oneshot::Receiver<Option<Transaction>> {
         let (tx, rx) = futures::channel::oneshot::channel();
         let prev_version = self.text.version();
-        self.reload_task = Some(cx.spawn(|this, mut cx| async move {
-            let Some((new_mtime, new_text)) = this.update(&mut cx, |this, cx| {
+        self.reload_task = Some(cx.spawn(async move |this, cx| {
+            let Some((new_mtime, new_text)) = this.update(cx, |this, cx| {
                 let file = this.file.as_ref()?.as_local()?;
                 Some((file.disk_state().mtime(), file.load(cx)))
             })?
@@ -1315,9 +1315,9 @@ impl Buffer {
 
             let new_text = new_text.await?;
             let diff = this
-                .update(&mut cx, |this, cx| this.diff(new_text.clone(), cx))?
+                .update(cx, |this, cx| this.diff(new_text.clone(), cx))?
                 .await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 if this.version() == diff.base_version {
                     this.finalize_last_transaction();
                     this.apply_diff(diff, cx);
@@ -1499,9 +1499,9 @@ impl Buffer {
                 self.reparse = None;
             }
             Err(parse_task) => {
-                self.reparse = Some(cx.spawn(move |this, mut cx| async move {
+                self.reparse = Some(cx.spawn(async move |this, cx| {
                     let new_syntax_map = parse_task.await;
-                    this.update(&mut cx, move |this, cx| {
+                    this.update(cx, move |this, cx| {
                         let grammar_changed =
                             this.language.as_ref().map_or(true, |current_language| {
                                 !Arc::ptr_eq(&language, current_language)
@@ -1566,9 +1566,9 @@ impl Buffer {
             {
                 Ok(indent_sizes) => self.apply_autoindents(indent_sizes, cx),
                 Err(indent_sizes) => {
-                    self.pending_autoindent = Some(cx.spawn(|this, mut cx| async move {
+                    self.pending_autoindent = Some(cx.spawn(async move |this, cx| {
                         let indent_sizes = indent_sizes.await;
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             this.apply_autoindents(indent_sizes, cx);
                         })
                         .ok();

crates/language/src/language_registry.rs 🔗

@@ -940,7 +940,7 @@ impl LanguageRegistry {
         server_id: LanguageServerId,
         name: &LanguageServerName,
         binary: lsp::LanguageServerBinary,
-        cx: gpui::AsyncApp,
+        cx: &mut gpui::AsyncApp,
     ) -> Option<lsp::LanguageServer> {
         use gpui::AppContext as _;
 
@@ -951,7 +951,7 @@ impl LanguageRegistry {
             binary,
             name.0.to_string(),
             fake_entry.capabilities.clone(),
-            cx.clone(),
+            cx,
         );
         fake_entry._server = Some(fake_server.clone());
 

crates/language_model_selector/src/language_model_selector.rs 🔗

@@ -102,7 +102,7 @@ impl LanguageModelSelector {
             .map(|provider| (provider.id(), provider.name(), provider.authenticate(cx)))
             .collect::<Vec<_>>();
 
-        cx.spawn(|_cx| async move {
+        cx.spawn(async move |_cx| {
             for (provider_id, provider_name, authenticate_task) in authenticate_all_providers {
                 if let Err(err) = authenticate_task.await {
                     if matches!(err, AuthenticateError::CredentialsNotFound) {
@@ -300,7 +300,7 @@ impl PickerDelegate for LanguageModelPickerDelegate {
             .map(|provider| provider.id())
             .collect::<Vec<_>>();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let filtered_models = cx
                 .background_spawn(async move {
                     let displayed_models = if configured_providers.is_empty() {
@@ -332,7 +332,7 @@ impl PickerDelegate for LanguageModelPickerDelegate {
                 })
                 .await;
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.delegate.filtered_models = filtered_models;
                 // Preserve selection focus
                 let new_index = if current_index >= this.delegate.filtered_models.len() {

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

@@ -77,12 +77,12 @@ impl State {
             .anthropic
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .delete_credentials(&api_url, &cx)
                 .await
                 .ok();
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = None;
                 this.api_key_from_env = false;
                 cx.notify();
@@ -96,13 +96,13 @@ impl State {
             .anthropic
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .write_credentials(&api_url, "Bearer", api_key.as_bytes(), &cx)
                 .await
                 .ok();
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 cx.notify();
             })
@@ -124,7 +124,7 @@ impl State {
             .api_url
             .clone();
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (api_key, from_env) = if let Ok(api_key) = std::env::var(ANTHROPIC_API_KEY_VAR) {
                 (api_key, true)
             } else {
@@ -138,7 +138,7 @@ impl State {
                 )
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 this.api_key_from_env = from_env;
                 cx.notify();
@@ -760,15 +760,15 @@ impl ConfigurationView {
 
         let load_credentials_task = Some(cx.spawn({
             let state = state.clone();
-            |this, mut cx| async move {
+            async move |this, cx| {
                 if let Some(task) = state
-                    .update(&mut cx, |state, cx| state.authenticate(cx))
+                    .update(cx, |state, cx| state.authenticate(cx))
                     .log_err()
                 {
                     // We don't log an error, because "not signed in" is also an error.
                     let _ = task.await;
                 }
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.load_credentials_task = None;
                     cx.notify();
                 })
@@ -794,9 +794,9 @@ impl ConfigurationView {
         }
 
         let state = self.state.clone();
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             state
-                .update(&mut cx, |state, cx| state.set_api_key(api_key, cx))?
+                .update(cx, |state, cx| state.set_api_key(api_key, cx))?
                 .await
         })
         .detach_and_log_err(cx);
@@ -809,10 +809,8 @@ impl ConfigurationView {
             .update(cx, |editor, cx| editor.set_text("", window, cx));
 
         let state = self.state.clone();
-        cx.spawn_in(window, |_, mut cx| async move {
-            state
-                .update(&mut cx, |state, cx| state.reset_api_key(cx))?
-                .await
+        cx.spawn_in(window, async move |_, cx| {
+            state.update(cx, |state, cx| state.reset_api_key(cx))?.await
         })
         .detach_and_log_err(cx);
 

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

@@ -90,12 +90,12 @@ pub struct State {
 impl State {
     fn reset_credentials(&self, cx: &mut Context<Self>) -> Task<Result<()>> {
         let credentials_provider = <dyn CredentialsProvider>::global(cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .delete_credentials(AMAZON_AWS_URL, &cx)
                 .await
                 .log_err();
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.credentials = None;
                 this.credentials_from_env = false;
                 cx.notify();
@@ -109,7 +109,7 @@ impl State {
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
         let credentials_provider = <dyn CredentialsProvider>::global(cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .write_credentials(
                     AMAZON_AWS_URL,
@@ -118,7 +118,7 @@ impl State {
                     &cx,
                 )
                 .await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.credentials = Some(credentials);
                 cx.notify();
             })
@@ -135,7 +135,7 @@ impl State {
         }
 
         let credentials_provider = <dyn CredentialsProvider>::global(cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (credentials, from_env) =
                 if let Ok(credentials) = std::env::var(ZED_AWS_CREDENTIALS_VAR) {
                     (credentials, true)
@@ -154,7 +154,7 @@ impl State {
             let credentials: BedrockCredentials =
                 serde_json::from_str(&credentials).context("failed to parse credentials")?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.credentials = Some(credentials);
                 this.credentials_from_env = from_env;
                 cx.notify();
@@ -789,15 +789,15 @@ impl ConfigurationView {
 
         let load_credentials_task = Some(cx.spawn({
             let state = state.clone();
-            |this, mut cx| async move {
+            async move |this, cx| {
                 if let Some(task) = state
-                    .update(&mut cx, |state, cx| state.authenticate(cx))
+                    .update(cx, |state, cx| state.authenticate(cx))
                     .log_err()
                 {
                     // We don't log an error, because "not signed in" is also an error.
                     let _ = task.await;
                 }
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.load_credentials_task = None;
                     cx.notify();
                 })
@@ -855,9 +855,9 @@ impl ConfigurationView {
             .to_string();
 
         let state = self.state.clone();
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             state
-                .update(&mut cx, |state, cx| {
+                .update(cx, |state, cx| {
                     let credentials: BedrockCredentials = BedrockCredentials {
                         access_key_id: access_key_id.clone(),
                         secret_access_key: secret_access_key.clone(),
@@ -880,9 +880,9 @@ impl ConfigurationView {
             .update(cx, |editor, cx| editor.set_text("", window, cx));
 
         let state = self.state.clone();
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             state
-                .update(&mut cx, |state, cx| state.reset_credentials(cx))?
+                .update(cx, |state, cx| state.reset_credentials(cx))?
                 .await
         })
         .detach_and_log_err(cx);

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

@@ -132,7 +132,7 @@ impl State {
                 |this, _listener, _event, cx| {
                     let client = this.client.clone();
                     let llm_api_token = this.llm_api_token.clone();
-                    cx.spawn(|_this, _cx| async move {
+                    cx.spawn(async move |_this, _cx| {
                         llm_api_token.refresh(&client).await?;
                         anyhow::Ok(())
                     })
@@ -148,9 +148,9 @@ impl State {
 
     fn authenticate(&self, cx: &mut Context<Self>) -> Task<Result<()>> {
         let client = self.client.clone();
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             client.authenticate_and_connect(true, &cx).await?;
-            this.update(&mut cx, |_, cx| cx.notify())
+            this.update(cx, |_, cx| cx.notify())
         })
     }
 
@@ -163,11 +163,11 @@ impl State {
 
     fn accept_terms_of_service(&mut self, cx: &mut Context<Self>) {
         let user_store = self.user_store.clone();
-        self.accept_terms = Some(cx.spawn(move |this, mut cx| async move {
+        self.accept_terms = Some(cx.spawn(async move |this, cx| {
             let _ = user_store
-                .update(&mut cx, |store, cx| store.accept_terms_of_service(cx))?
+                .update(cx, |store, cx| store.accept_terms_of_service(cx))?
                 .await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.accept_terms = None;
                 cx.notify()
             })
@@ -183,10 +183,10 @@ impl CloudLanguageModelProvider {
         let state = cx.new(|cx| State::new(client.clone(), user_store.clone(), status, cx));
 
         let state_ref = state.downgrade();
-        let maintain_client_status = cx.spawn(|mut cx| async move {
+        let maintain_client_status = cx.spawn(async move |cx| {
             while let Some(status) = status_rx.next().await {
                 if let Some(this) = state_ref.upgrade() {
-                    _ = this.update(&mut cx, |this, cx| {
+                    _ = this.update(cx, |this, cx| {
                         if this.status != status {
                             this.status = status;
                             cx.notify();

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

@@ -229,8 +229,8 @@ impl LanguageModel for CopilotChatLanguageModel {
         let is_streaming = copilot_request.stream;
 
         let request_limiter = self.request_limiter.clone();
-        let future = cx.spawn(|cx| async move {
-            let response = CopilotChat::stream_completion(copilot_request, cx);
+        let future = cx.spawn(async move |cx| {
+            let response = CopilotChat::stream_completion(copilot_request, cx.clone());
             request_limiter.stream(async move {
                 let response = response.await?;
                 let stream = response
@@ -264,6 +264,7 @@ impl LanguageModel for CopilotChatLanguageModel {
                         }
                     })
                     .boxed();
+
                 Ok(stream)
             }).await
         });

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

@@ -63,12 +63,12 @@ impl State {
             .deepseek
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .delete_credentials(&api_url, &cx)
                 .await
                 .log_err();
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = None;
                 this.api_key_from_env = false;
                 cx.notify();
@@ -82,11 +82,11 @@ impl State {
             .deepseek
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .write_credentials(&api_url, "Bearer", api_key.as_bytes(), &cx)
                 .await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 cx.notify();
             })
@@ -103,7 +103,7 @@ impl State {
             .deepseek
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (api_key, from_env) = if let Ok(api_key) = std::env::var(DEEPSEEK_API_KEY_VAR) {
                 (api_key, true)
             } else {
@@ -117,7 +117,7 @@ impl State {
                 )
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 this.api_key_from_env = from_env;
                 cx.notify();
@@ -517,15 +517,15 @@ impl ConfigurationView {
 
         let load_credentials_task = Some(cx.spawn({
             let state = state.clone();
-            |this, mut cx| async move {
+            async move |this, cx| {
                 if let Some(task) = state
-                    .update(&mut cx, |state, cx| state.authenticate(cx))
+                    .update(cx, |state, cx| state.authenticate(cx))
                     .log_err()
                 {
                     let _ = task.await;
                 }
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.load_credentials_task = None;
                     cx.notify();
                 })
@@ -547,9 +547,9 @@ impl ConfigurationView {
         }
 
         let state = self.state.clone();
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             state
-                .update(&mut cx, |state, cx| state.set_api_key(api_key, cx))?
+                .update(cx, |state, cx| state.set_api_key(api_key, cx))?
                 .await
         })
         .detach_and_log_err(cx);
@@ -562,12 +562,8 @@ impl ConfigurationView {
             .update(cx, |editor, cx| editor.set_text("", window, cx));
 
         let state = self.state.clone();
-        cx.spawn(|_, mut cx| async move {
-            state
-                .update(&mut cx, |state, cx| state.reset_api_key(cx))?
-                .await
-        })
-        .detach_and_log_err(cx);
+        cx.spawn(async move |_, cx| state.update(cx, |state, cx| state.reset_api_key(cx))?.await)
+            .detach_and_log_err(cx);
 
         cx.notify();
     }

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

@@ -66,12 +66,12 @@ impl State {
             .google
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .delete_credentials(&api_url, &cx)
                 .await
                 .log_err();
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = None;
                 this.api_key_from_env = false;
                 cx.notify();
@@ -85,11 +85,11 @@ impl State {
             .google
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .write_credentials(&api_url, "Bearer", api_key.as_bytes(), &cx)
                 .await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 cx.notify();
             })
@@ -107,7 +107,7 @@ impl State {
             .api_url
             .clone();
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (api_key, from_env) = if let Ok(api_key) = std::env::var(GOOGLE_AI_API_KEY_VAR) {
                 (api_key, true)
             } else {
@@ -121,7 +121,7 @@ impl State {
                 )
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 this.api_key_from_env = from_env;
                 cx.notify();
@@ -418,15 +418,15 @@ impl ConfigurationView {
 
         let load_credentials_task = Some(cx.spawn_in(window, {
             let state = state.clone();
-            |this, mut cx| async move {
+            async move |this, cx| {
                 if let Some(task) = state
-                    .update(&mut cx, |state, cx| state.authenticate(cx))
+                    .update(cx, |state, cx| state.authenticate(cx))
                     .log_err()
                 {
                     // We don't log an error, because "not signed in" is also an error.
                     let _ = task.await;
                 }
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.load_credentials_task = None;
                     cx.notify();
                 })
@@ -452,9 +452,9 @@ impl ConfigurationView {
         }
 
         let state = self.state.clone();
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             state
-                .update(&mut cx, |state, cx| state.set_api_key(api_key, cx))?
+                .update(cx, |state, cx| state.set_api_key(api_key, cx))?
                 .await
         })
         .detach_and_log_err(cx);
@@ -467,10 +467,8 @@ impl ConfigurationView {
             .update(cx, |editor, cx| editor.set_text("", window, cx));
 
         let state = self.state.clone();
-        cx.spawn_in(window, |_, mut cx| async move {
-            state
-                .update(&mut cx, |state, cx| state.reset_api_key(cx))?
-                .await
+        cx.spawn_in(window, async move |_, cx| {
+            state.update(cx, |state, cx| state.reset_api_key(cx))?.await
         })
         .detach_and_log_err(cx);
 

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

@@ -67,7 +67,7 @@ impl State {
         let api_url = settings.api_url.clone();
 
         // As a proxy for the server being "authenticated", we'll check if its up by fetching the models
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let models = get_models(http_client.as_ref(), &api_url, None).await?;
 
             let mut models: Vec<lmstudio::Model> = models
@@ -78,7 +78,7 @@ impl State {
 
             models.sort_by(|a, b| a.name.cmp(&b.name));
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.available_models = models;
                 cx.notify();
             })
@@ -96,7 +96,7 @@ impl State {
         }
 
         let fetch_models_task = self.fetch_models(cx);
-        cx.spawn(|_this, _cx| async move { Ok(fetch_models_task.await?) })
+        cx.spawn(async move |_this, _cx| Ok(fetch_models_task.await?))
     }
 }
 
@@ -198,7 +198,7 @@ impl LanguageModelProvider for LmStudioLanguageModelProvider {
         let http_client = self.http_client.clone();
         let api_url = settings.api_url.clone();
         let id = model.id().0.to_string();
-        cx.spawn(|_| async move { preload_model(http_client, &api_url, &id).await })
+        cx.spawn(async move |_| preload_model(http_client, &api_url, &id).await)
             .detach_and_log_err(cx);
     }
 
@@ -382,14 +382,14 @@ impl ConfigurationView {
     pub fn new(state: gpui::Entity<State>, cx: &mut Context<Self>) -> Self {
         let loading_models_task = Some(cx.spawn({
             let state = state.clone();
-            |this, mut cx| async move {
+            async move |this, cx| {
                 if let Some(task) = state
-                    .update(&mut cx, |state, cx| state.authenticate(cx))
+                    .update(cx, |state, cx| state.authenticate(cx))
                     .log_err()
                 {
                     task.await.log_err();
                 }
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.loading_models_task = None;
                     cx.notify();
                 })

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

@@ -68,12 +68,12 @@ impl State {
             .mistral
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .delete_credentials(&api_url, &cx)
                 .await
                 .log_err();
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = None;
                 this.api_key_from_env = false;
                 cx.notify();
@@ -87,11 +87,11 @@ impl State {
             .mistral
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .write_credentials(&api_url, "Bearer", api_key.as_bytes(), &cx)
                 .await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 cx.notify();
             })
@@ -108,7 +108,7 @@ impl State {
             .mistral
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (api_key, from_env) = if let Ok(api_key) = std::env::var(MISTRAL_API_KEY_VAR) {
                 (api_key, true)
             } else {
@@ -121,7 +121,7 @@ impl State {
                     false,
                 )
             };
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 this.api_key_from_env = from_env;
                 cx.notify();
@@ -482,16 +482,16 @@ impl ConfigurationView {
 
         let load_credentials_task = Some(cx.spawn_in(window, {
             let state = state.clone();
-            |this, mut cx| async move {
+            async move |this, cx| {
                 if let Some(task) = state
-                    .update(&mut cx, |state, cx| state.authenticate(cx))
+                    .update(cx, |state, cx| state.authenticate(cx))
                     .log_err()
                 {
                     // We don't log an error, because "not signed in" is also an error.
                     let _ = task.await;
                 }
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.load_credentials_task = None;
                     cx.notify();
                 })
@@ -513,9 +513,9 @@ impl ConfigurationView {
         }
 
         let state = self.state.clone();
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             state
-                .update(&mut cx, |state, cx| state.set_api_key(api_key, cx))?
+                .update(cx, |state, cx| state.set_api_key(api_key, cx))?
                 .await
         })
         .detach_and_log_err(cx);
@@ -528,10 +528,8 @@ impl ConfigurationView {
             .update(cx, |editor, cx| editor.set_text("", window, cx));
 
         let state = self.state.clone();
-        cx.spawn_in(window, |_, mut cx| async move {
-            state
-                .update(&mut cx, |state, cx| state.reset_api_key(cx))?
-                .await
+        cx.spawn_in(window, async move |_, cx| {
+            state.update(cx, |state, cx| state.reset_api_key(cx))?.await
         })
         .detach_and_log_err(cx);
 

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

@@ -69,7 +69,7 @@ impl State {
         let api_url = settings.api_url.clone();
 
         // As a proxy for the server being "authenticated", we'll check if its up by fetching the models
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let models = get_models(http_client.as_ref(), &api_url, None).await?;
 
             let mut models: Vec<ollama::Model> = models
@@ -83,7 +83,7 @@ impl State {
 
             models.sort_by(|a, b| a.name.cmp(&b.name));
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.available_models = models;
                 cx.notify();
             })
@@ -101,7 +101,7 @@ impl State {
         }
 
         let fetch_models_task = self.fetch_models(cx);
-        cx.spawn(|_this, _cx| async move { Ok(fetch_models_task.await?) })
+        cx.spawn(async move |_this, _cx| Ok(fetch_models_task.await?))
     }
 }
 
@@ -204,7 +204,7 @@ impl LanguageModelProvider for OllamaLanguageModelProvider {
         let http_client = self.http_client.clone();
         let api_url = settings.api_url.clone();
         let id = model.id().0.to_string();
-        cx.spawn(|_| async move { preload_model(http_client, &api_url, &id).await })
+        cx.spawn(async move |_| preload_model(http_client, &api_url, &id).await)
             .detach_and_log_err(cx);
     }
 
@@ -421,14 +421,14 @@ impl ConfigurationView {
     pub fn new(state: gpui::Entity<State>, window: &mut Window, cx: &mut Context<Self>) -> Self {
         let loading_models_task = Some(cx.spawn_in(window, {
             let state = state.clone();
-            |this, mut cx| async move {
+            async move |this, cx| {
                 if let Some(task) = state
-                    .update(&mut cx, |state, cx| state.authenticate(cx))
+                    .update(cx, |state, cx| state.authenticate(cx))
                     .log_err()
                 {
                     task.await.log_err();
                 }
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.loading_models_task = None;
                     cx.notify();
                 })

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

@@ -69,12 +69,12 @@ impl State {
             .openai
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .delete_credentials(&api_url, &cx)
                 .await
                 .log_err();
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = None;
                 this.api_key_from_env = false;
                 cx.notify();
@@ -88,12 +88,12 @@ impl State {
             .openai
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             credentials_provider
                 .write_credentials(&api_url, "Bearer", api_key.as_bytes(), &cx)
                 .await
                 .log_err();
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 cx.notify();
             })
@@ -110,7 +110,7 @@ impl State {
             .openai
             .api_url
             .clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (api_key, from_env) = if let Ok(api_key) = std::env::var(OPENAI_API_KEY_VAR) {
                 (api_key, true)
             } else {
@@ -123,7 +123,7 @@ impl State {
                     false,
                 )
             };
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.api_key = Some(api_key);
                 this.api_key_from_env = from_env;
                 cx.notify();
@@ -452,16 +452,16 @@ impl ConfigurationView {
 
         let load_credentials_task = Some(cx.spawn_in(window, {
             let state = state.clone();
-            |this, mut cx| async move {
+            async move |this, cx| {
                 if let Some(task) = state
-                    .update(&mut cx, |state, cx| state.authenticate(cx))
+                    .update(cx, |state, cx| state.authenticate(cx))
                     .log_err()
                 {
                     // We don't log an error, because "not signed in" is also an error.
                     let _ = task.await;
                 }
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.load_credentials_task = None;
                     cx.notify();
                 })
@@ -483,9 +483,9 @@ impl ConfigurationView {
         }
 
         let state = self.state.clone();
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             state
-                .update(&mut cx, |state, cx| state.set_api_key(api_key, cx))?
+                .update(cx, |state, cx| state.set_api_key(api_key, cx))?
                 .await
         })
         .detach_and_log_err(cx);
@@ -498,10 +498,8 @@ impl ConfigurationView {
             .update(cx, |editor, cx| editor.set_text("", window, cx));
 
         let state = self.state.clone();
-        cx.spawn_in(window, |_, mut cx| async move {
-            state
-                .update(&mut cx, |state, cx| state.reset_api_key(cx))?
-                .await
+        cx.spawn_in(window, async move |_, cx| {
+            state.update(cx, |state, cx| state.reset_api_key(cx))?.await
         })
         .detach_and_log_err(cx);
 

crates/language_selector/src/language_selector.rs 🔗

@@ -190,7 +190,7 @@ impl PickerDelegate for LanguageSelectorDelegate {
             let language = self.language_registry.language_for_name(language_name);
             let project = self.project.downgrade();
             let buffer = self.buffer.downgrade();
-            cx.spawn_in(window, |_, mut cx| async move {
+            cx.spawn_in(window, async move |_, cx| {
                 let language = language.await?;
                 let project = project
                     .upgrade()
@@ -198,7 +198,7 @@ impl PickerDelegate for LanguageSelectorDelegate {
                 let buffer = buffer
                     .upgrade()
                     .ok_or_else(|| anyhow!("buffer was dropped"))?;
-                project.update(&mut cx, |project, cx| {
+                project.update(cx, |project, cx| {
                     project.set_language_for_buffer(&buffer, language, cx);
                 })
             })
@@ -234,7 +234,7 @@ impl PickerDelegate for LanguageSelectorDelegate {
     ) -> gpui::Task<()> {
         let background = cx.background_executor().clone();
         let candidates = self.candidates.clone();
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let matches = if query.is_empty() {
                 candidates
                     .into_iter()
@@ -258,7 +258,7 @@ impl PickerDelegate for LanguageSelectorDelegate {
                 .await
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let delegate = &mut this.delegate;
                 delegate.matches = matches;
                 delegate.selected_index = delegate

crates/language_tools/src/lsp_log.rs 🔗

@@ -245,9 +245,9 @@ impl LogStore {
                         let weak_this = cx.weak_entity();
                         this.copilot_log_subscription =
                             Some(server.on_notification::<copilot::request::LogMessage, _>(
-                                move |params, mut cx| {
+                                move |params, cx| {
                                     weak_this
-                                        .update(&mut cx, |this, cx| {
+                                        .update(cx, |this, cx| {
                                             this.add_language_server_log(
                                                 server_id,
                                                 MessageType::LOG,
@@ -280,10 +280,10 @@ impl LogStore {
             io_tx,
         };
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             while let Some((server_id, io_kind, message)) = io_rx.next().await {
                 if let Some(this) = this.upgrade() {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.on_io(server_id, io_kind, &message, cx);
                     })?;
                 }
@@ -936,9 +936,9 @@ impl LspLogView {
                 .update(cx, |_, cx| {
                     cx.spawn({
                         let buffer = cx.entity();
-                        |_, mut cx| async move {
+                        async move |_, cx| {
                             let language = language.await.ok();
-                            buffer.update(&mut cx, |buffer, cx| {
+                            buffer.update(cx, |buffer, cx| {
                                 buffer.set_language(language, cx);
                             })
                         }

crates/languages/src/go.rs 🔗

@@ -97,7 +97,7 @@ impl super::LspAdapter for GoLspAdapter {
             "Could not install the Go language server `gopls`, because `go` was not found.";
 
         let delegate = delegate.clone();
-        Some(cx.spawn(|cx| async move {
+        Some(cx.spawn(async move |cx| {
             if delegate.which("go".as_ref()).await.is_none() {
                 if DID_SHOW_NOTIFICATION
                     .compare_exchange(false, true, SeqCst, SeqCst)

crates/languages/src/lib.rs 🔗

@@ -284,7 +284,7 @@ pub fn init(languages: Arc<LanguageRegistry>, node: NodeRuntime, cx: &mut App) {
     let mut subscription = languages.subscribe();
     let mut prev_language_settings = languages.language_settings();
 
-    cx.spawn(|cx| async move {
+    cx.spawn(async move |cx| {
         while subscription.next().await.is_some() {
             let language_settings = languages.language_settings();
             if language_settings != prev_language_settings {

crates/languages/src/python.rs 🔗

@@ -339,10 +339,10 @@ impl ContextProvider for PythonContextProvider {
         };
 
         let worktree_id = location.buffer.read(cx).file().map(|f| f.worktree_id(cx));
-        cx.spawn(move |mut cx| async move {
+        cx.spawn(async move |cx| {
             let active_toolchain = if let Some(worktree_id) = worktree_id {
                 toolchains
-                    .active_toolchain(worktree_id, "Python".into(), &mut cx)
+                    .active_toolchain(worktree_id, "Python".into(), cx)
                     .await
                     .map_or_else(
                         || "python3".to_owned(),

crates/livekit_client/examples/test_app.rs 🔗

@@ -76,7 +76,7 @@ fn main() {
         let height = px(800.);
         let width = px(800.);
 
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             let mut windows = Vec::new();
             for i in 0..2 {
                 let token = token::create(
@@ -141,7 +141,7 @@ impl LivekitWindow {
                 },
                 |window, cx| {
                     cx.new(|cx| {
-                        let _events_task = cx.spawn_in(window, |this, mut cx| async move {
+                        let _events_task = cx.spawn_in(window, async move |this, cx| {
                             while let Some(event) = events.recv().await {
                                 cx.update(|window, cx| {
                                     this.update(cx, |this: &mut LivekitWindow, cx| {
@@ -276,7 +276,7 @@ impl LivekitWindow {
             cx.notify();
         } else {
             let participant = self.room.local_participant();
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 let (track, stream) = capture_local_audio_track(cx.background_executor())?.await;
                 let publication = participant
                     .publish_track(
@@ -288,7 +288,7 @@ impl LivekitWindow {
                     )
                     .await
                     .unwrap();
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.microphone_track = Some(publication);
                     this.microphone_stream = Some(stream);
                     cx.notify();
@@ -310,7 +310,7 @@ impl LivekitWindow {
         } else {
             let participant = self.room.local_participant();
             let sources = cx.screen_capture_sources();
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 let sources = sources.await.unwrap()?;
                 let source = sources.into_iter().next().unwrap();
                 let (track, stream) = capture_local_video_track(&*source).await?;
@@ -325,7 +325,7 @@ impl LivekitWindow {
                     )
                     .await
                     .unwrap();
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.screen_share_track = Some(publication);
                     this.screen_share_stream = Some(stream);
                     cx.notify();

crates/livekit_client/src/remote_video_track_view.rs 🔗

@@ -29,15 +29,15 @@ impl RemoteVideoTrackView {
         Self {
             track,
             latest_frame: None,
-            _maintain_frame: cx.spawn_in(window, |this, mut cx| async move {
+            _maintain_frame: cx.spawn_in(window, async move |this, cx| {
                 futures::pin_mut!(frames);
                 while let Some(frame) = frames.next().await {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.latest_frame = Some(frame);
                         cx.notify();
                     })?;
                 }
-                this.update(&mut cx, |_this, cx| {
+                this.update(cx, |_this, cx| {
                     #[cfg(not(target_os = "macos"))]
                     {
                         use util::ResultExt as _;

crates/livekit_client_macos/examples/test_app_macos.rs 🔗

@@ -37,7 +37,7 @@ fn main() {
         let live_kit_key = std::env::var("LIVE_KIT_KEY").unwrap_or("devkey".into());
         let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap_or("secret".into());
 
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             let user_a_token = token::create(
                 &live_kit_key,
                 &live_kit_secret,

crates/lsp/src/lsp.rs 🔗

@@ -47,7 +47,7 @@ const CONTENT_LEN_HEADER: &str = "Content-Length: ";
 const LSP_REQUEST_TIMEOUT: Duration = Duration::from_secs(60 * 2);
 const SERVER_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
 
-type NotificationHandler = Box<dyn Send + FnMut(Option<RequestId>, Value, AsyncApp)>;
+type NotificationHandler = Box<dyn Send + FnMut(Option<RequestId>, Value, &mut AsyncApp)>;
 type ResponseHandler = Box<dyn Send + FnOnce(Result<String, Error>)>;
 type IoHandler = Box<dyn Send + FnMut(IoKind, &str)>;
 
@@ -309,7 +309,7 @@ impl LanguageServer {
         root_path: &Path,
         code_action_kinds: Option<Vec<CodeActionKind>>,
         workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
-        cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<Self> {
         let working_dir = if root_path.is_dir() {
             root_path
@@ -383,7 +383,7 @@ impl LanguageServer {
         binary: LanguageServerBinary,
         root_uri: Url,
         workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
-        cx: AsyncApp,
+        cx: &mut AsyncApp,
         on_unhandled_notification: F,
     ) -> Self
     where
@@ -405,7 +405,7 @@ impl LanguageServer {
             let notification_handlers = notification_handlers.clone();
             let response_handlers = response_handlers.clone();
             let io_handlers = io_handlers.clone();
-            move |cx| {
+            async move |cx| {
                 Self::handle_input(
                     stdout,
                     on_unhandled_notification,
@@ -415,16 +415,21 @@ impl LanguageServer {
                     cx,
                 )
                 .log_err()
+                .await
             }
         });
         let stderr_input_task = stderr
             .map(|stderr| {
                 let io_handlers = io_handlers.clone();
                 let stderr_captures = stderr_capture.clone();
-                cx.spawn(|_| Self::handle_stderr(stderr, io_handlers, stderr_captures).log_err())
+                cx.spawn(async move |_| {
+                    Self::handle_stderr(stderr, io_handlers, stderr_captures)
+                        .log_err()
+                        .await
+                })
             })
             .unwrap_or_else(|| Task::ready(None));
-        let input_task = cx.spawn(|_| async move {
+        let input_task = cx.spawn(async move |_| {
             let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task);
             stdout.or(stderr)
         });
@@ -481,7 +486,7 @@ impl LanguageServer {
         notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
         response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
         io_handlers: Arc<Mutex<HashMap<i32, IoHandler>>>,
-        cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> anyhow::Result<()>
     where
         Stdout: AsyncRead + Unpin + Send + 'static,
@@ -506,7 +511,7 @@ impl LanguageServer {
             {
                 let mut notification_handlers = notification_handlers.lock();
                 if let Some(handler) = notification_handlers.get_mut(msg.method.as_str()) {
-                    handler(msg.id, msg.params.unwrap_or(Value::Null), cx.clone());
+                    handler(msg.id, msg.params.unwrap_or(Value::Null), cx);
                 } else {
                     drop(notification_handlers);
                     on_unhandled_notification(msg);
@@ -807,7 +812,7 @@ impl LanguageServer {
         configuration: Arc<DidChangeConfigurationParams>,
         cx: &App,
     ) -> Task<Result<Arc<Self>>> {
-        cx.spawn(|_| async move {
+        cx.spawn(async move |_| {
             let response = self.request::<request::Initialize>(params).await?;
             if let Some(info) = response.server_info {
                 self.process_name = info.name.into();
@@ -878,7 +883,7 @@ impl LanguageServer {
     pub fn on_notification<T, F>(&self, f: F) -> Subscription
     where
         T: notification::Notification,
-        F: 'static + Send + FnMut(T::Params, AsyncApp),
+        F: 'static + Send + FnMut(T::Params, &mut AsyncApp),
     {
         self.on_custom_notification(T::METHOD, f)
     }
@@ -891,7 +896,7 @@ impl LanguageServer {
     where
         T: request::Request,
         T::Params: 'static + Send,
-        F: 'static + FnMut(T::Params, AsyncApp) -> Fut + Send,
+        F: 'static + FnMut(T::Params, &mut AsyncApp) -> Fut + Send,
         Fut: 'static + Future<Output = Result<T::Result>>,
     {
         self.on_custom_request(T::METHOD, f)
@@ -929,7 +934,7 @@ impl LanguageServer {
     #[must_use]
     fn on_custom_notification<Params, F>(&self, method: &'static str, mut f: F) -> Subscription
     where
-        F: 'static + FnMut(Params, AsyncApp) + Send,
+        F: 'static + FnMut(Params, &mut AsyncApp) + Send,
         Params: DeserializeOwned,
     {
         let prev_handler = self.notification_handlers.lock().insert(
@@ -953,7 +958,7 @@ impl LanguageServer {
     #[must_use]
     fn on_custom_request<Params, Res, Fut, F>(&self, method: &'static str, mut f: F) -> Subscription
     where
-        F: 'static + FnMut(Params, AsyncApp) -> Fut + Send,
+        F: 'static + FnMut(Params, &mut AsyncApp) -> Fut + Send,
         Fut: 'static + Future<Output = Result<Res>>,
         Params: DeserializeOwned + Send + 'static,
         Res: Serialize,
@@ -965,7 +970,7 @@ impl LanguageServer {
                 if let Some(id) = id {
                     match serde_json::from_value(params) {
                         Ok(params) => {
-                            let response = f(params, cx.clone());
+                            let response = f(params, cx);
                             cx.foreground_executor()
                                 .spawn({
                                     let outbound_tx = outbound_tx.clone();
@@ -1379,7 +1384,7 @@ impl FakeLanguageServer {
         binary: LanguageServerBinary,
         name: String,
         capabilities: ServerCapabilities,
-        cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> (LanguageServer, FakeLanguageServer) {
         let (stdin_writer, stdin_reader) = async_pipe::pipe();
         let (stdout_writer, stdout_reader) = async_pipe::pipe();
@@ -1401,7 +1406,7 @@ impl FakeLanguageServer {
             binary.clone(),
             root,
             workspace_folders.clone(),
-            cx.clone(),
+            cx,
             |_| {},
         );
         server.process_name = process_name;
@@ -1420,7 +1425,7 @@ impl FakeLanguageServer {
                     binary,
                     Self::root_path(),
                     workspace_folders,
-                    cx.clone(),
+                    cx,
                     move |msg| {
                         notifications_tx
                             .try_send((
@@ -1634,7 +1639,7 @@ mod tests {
             },
             "the-lsp".to_string(),
             Default::default(),
-            cx.to_async(),
+            &mut cx.to_async(),
         );
 
         let (message_tx, message_rx) = channel::unbounded();

crates/markdown/src/markdown.rs 🔗

@@ -231,10 +231,10 @@ impl Markdown {
         });
 
         self.should_reparse = false;
-        self.pending_parse = Some(cx.spawn(|this, mut cx| {
+        self.pending_parse = Some(cx.spawn(async move |this, cx| {
             async move {
                 let parsed = parsed.await?;
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.parsed_markdown = parsed;
                     this.pending_parse.take();
                     if this.should_reparse {
@@ -246,6 +246,7 @@ impl Markdown {
                 anyhow::Ok(())
             }
             .log_err()
+            .await
         }));
     }
 
@@ -795,7 +796,7 @@ impl Element for MarkdownElement {
                                                     code.clone(),
                                                 ));
 
-                                                cx.spawn(|this, cx| async move {
+                                                cx.spawn(async move |this, cx| {
                                                     cx.background_executor()
                                                         .timer(Duration::from_secs(2))
                                                         .await;

crates/markdown_preview/src/markdown_preview_view.rs 🔗

@@ -372,13 +372,13 @@ impl MarkdownPreviewView {
     ) -> Task<Result<()>> {
         let language_registry = self.language_registry.clone();
 
-        cx.spawn_in(window, move |view, mut cx| async move {
+        cx.spawn_in(window, async move |view, cx| {
             if wait_for_debounce {
                 // Wait for the user to stop typing
                 cx.background_executor().timer(REPARSE_DEBOUNCE).await;
             }
 
-            let (contents, file_location) = view.update(&mut cx, |_, cx| {
+            let (contents, file_location) = view.update(cx, |_, cx| {
                 let editor = editor.read(cx);
                 let contents = editor.buffer().read(cx).snapshot(cx).text();
                 let file_location = MarkdownPreviewView::get_folder_for_active_editor(editor, cx);
@@ -389,7 +389,7 @@ impl MarkdownPreviewView {
                 parse_markdown(&contents, file_location, Some(language_registry)).await
             });
             let contents = parsing_task.await;
-            view.update(&mut cx, move |view, cx| {
+            view.update(cx, move |view, cx| {
                 let markdown_blocks_count = contents.children.len();
                 view.contents = Some(contents);
                 let scroll_top = view.list_state.logical_scroll_top();

crates/multi_buffer/src/multi_buffer.rs 🔗

@@ -1752,7 +1752,7 @@ impl MultiBuffer {
             .detach()
         }
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let mut results_by_buffer_id = HashMap::default();
             while let Some((buffer_id, buffer, ranges, excerpt_ranges, range_counts)) =
                 excerpt_ranges_rx.next().await
@@ -1772,7 +1772,7 @@ impl MultiBuffer {
                 let mut ranges = ranges.into_iter();
                 let mut range_counts = range_counts.into_iter();
                 for excerpt_ranges in excerpt_ranges.chunks(100) {
-                    let excerpt_ids = match this.update(&mut cx, |this, cx| {
+                    let excerpt_ids = match this.update(cx, |this, cx| {
                         this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx)
                     }) {
                         Ok(excerpt_ids) => excerpt_ids,

crates/notifications/src/notification_store.rs 🔗

@@ -76,20 +76,20 @@ impl NotificationStore {
 
     pub fn new(client: Arc<Client>, user_store: Entity<UserStore>, cx: &mut Context<Self>) -> Self {
         let mut connection_status = client.status();
-        let watch_connection_status = cx.spawn(|this, mut cx| async move {
+        let watch_connection_status = cx.spawn(async move |this, cx| {
             while let Some(status) = connection_status.next().await {
                 let this = this.upgrade()?;
                 match status {
                     client::Status::Connected { .. } => {
                         if let Some(task) = this
-                            .update(&mut cx, |this, cx| this.handle_connect(cx))
+                            .update(cx, |this, cx| this.handle_connect(cx))
                             .log_err()?
                         {
                             task.await.log_err()?;
                         }
                     }
                     _ => this
-                        .update(&mut cx, |this, cx| this.handle_disconnect(cx))
+                        .update(cx, |this, cx| this.handle_disconnect(cx))
                         .log_err()?,
                 }
             }
@@ -161,15 +161,13 @@ impl NotificationStore {
             self.notifications.first().map(|entry| entry.id)
         };
         let request = self.client.request(proto::GetNotifications { before_id });
-        Some(cx.spawn(|this, mut cx| async move {
+        Some(cx.spawn(async move |this, cx| {
             let this = this
                 .upgrade()
                 .context("Notification store was dropped while loading notifications")?;
 
             let response = request.await?;
-            this.update(&mut cx, |this, _| {
-                this.loaded_all_notifications = response.done
-            })?;
+            this.update(cx, |this, _| this.loaded_all_notifications = response.done)?;
             Self::add_notifications(
                 this,
                 response.notifications,
@@ -199,7 +197,7 @@ impl NotificationStore {
     async fn handle_new_notification(
         this: Entity<Self>,
         envelope: TypedEnvelope<proto::AddNotification>,
-        cx: AsyncApp,
+        mut cx: AsyncApp,
     ) -> Result<()> {
         Self::add_notifications(
             this,
@@ -209,7 +207,7 @@ impl NotificationStore {
                 clear_old: false,
                 includes_first: false,
             },
-            cx,
+            &mut cx,
         )
         .await
     }
@@ -239,9 +237,9 @@ impl NotificationStore {
                         this.fetch_channel_messages(vec![message_id], cx)
                     });
 
-                    cx.spawn(|this, mut cx| async move {
+                    cx.spawn(async move |this, cx| {
                         let messages = fetch_message_task.await?;
-                        this.update(&mut cx, move |this, cx| {
+                        this.update(cx, move |this, cx| {
                             for message in messages {
                                 this.channel_messages.insert(message_id, message);
                             }
@@ -259,7 +257,7 @@ impl NotificationStore {
         this: Entity<Self>,
         notifications: Vec<proto::Notification>,
         options: AddNotificationsOptions,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<()> {
         let mut user_ids = Vec::new();
         let mut message_ids = Vec::new();
@@ -307,19 +305,19 @@ impl NotificationStore {
             }
         }
 
-        let (user_store, channel_store) = this.read_with(&cx, |this, _| {
+        let (user_store, channel_store) = this.read_with(cx, |this, _| {
             (this.user_store.clone(), this.channel_store.clone())
         })?;
 
         user_store
-            .update(&mut cx, |store, cx| store.get_users(user_ids, cx))?
+            .update(cx, |store, cx| store.get_users(user_ids, cx))?
             .await?;
         let messages = channel_store
-            .update(&mut cx, |store, cx| {
+            .update(cx, |store, cx| {
                 store.fetch_channel_messages(message_ids, cx)
             })?
             .await?;
-        this.update(&mut cx, |this, cx| {
+        this.update(cx, |this, cx| {
             if options.clear_old {
                 cx.emit(NotificationEvent::NotificationsUpdated {
                     old_range: 0..this.notifications.summary().count,

crates/outline_panel/src/outline_panel.rs 🔗

@@ -246,7 +246,7 @@ impl SearchState {
                     );
                 }
             }),
-            _search_match_notify: cx.spawn_in(window, |outline_panel, mut cx| async move {
+            _search_match_notify: cx.spawn_in(window, async move |outline_panel, cx| {
                 loop {
                     match notify_rx.recv().await {
                         Ok(()) => {}
@@ -255,7 +255,7 @@ impl SearchState {
                     while let Ok(()) = notify_rx.try_recv() {
                         //
                     }
-                    let update_result = outline_panel.update(&mut cx, |_, cx| {
+                    let update_result = outline_panel.update(cx, |_, cx| {
                         cx.notify();
                     });
                     if update_result.is_err() {
@@ -1794,9 +1794,9 @@ impl OutlinePanel {
         let Some(active_editor) = self.active_editor() else {
             return Task::ready(());
         };
-        cx.spawn_in(window, |outline_panel, mut cx| async move {
+        cx.spawn_in(window, async move |outline_panel, cx| {
             outline_panel
-                .update_in(&mut cx, |outline_panel, window, cx| {
+                .update_in(cx, |outline_panel, window, cx| {
                     active_editor.update(cx, |editor, cx| {
                         for buffer_id in buffers {
                             outline_panel
@@ -1906,14 +1906,14 @@ impl OutlinePanel {
             return;
         }
         let project = self.project.clone();
-        self.reveal_selection_task = cx.spawn_in(window, |outline_panel, mut cx| async move {
+        self.reveal_selection_task = cx.spawn_in(window, async move |outline_panel, cx| {
             cx.background_executor().timer(UPDATE_DEBOUNCE).await;
             let entry_with_selection =
-                outline_panel.update_in(&mut cx, |outline_panel, window, cx| {
+                outline_panel.update_in(cx, |outline_panel, window, cx| {
                     outline_panel.location_for_editor_selection(&editor, window, cx)
                 })?;
             let Some(entry_with_selection) = entry_with_selection else {
-                outline_panel.update(&mut cx, |outline_panel, cx| {
+                outline_panel.update(cx, |outline_panel, cx| {
                     outline_panel.selected_entry = SelectedEntry::None;
                     cx.notify();
                 })?;
@@ -1924,7 +1924,7 @@ impl OutlinePanel {
                     worktree_id,
                     buffer_id,
                     ..
-                })) => project.update(&mut cx, |project, cx| {
+                })) => project.update(cx, |project, cx| {
                     let entry_id = project
                         .buffer_for_id(*buffer_id, cx)
                         .and_then(|buffer| buffer.read(cx).entry_id(cx));
@@ -1938,7 +1938,7 @@ impl OutlinePanel {
                 })?,
                 PanelEntry::Outline(outline_entry) => {
                     let (buffer_id, excerpt_id) = outline_entry.ids();
-                    outline_panel.update(&mut cx, |outline_panel, cx| {
+                    outline_panel.update(cx, |outline_panel, cx| {
                         outline_panel
                             .collapsed_entries
                             .remove(&CollapsedEntry::ExternalFile(buffer_id));
@@ -1970,7 +1970,7 @@ impl OutlinePanel {
                     .buffer_id
                     .or(match_range.end.buffer_id)
                     .map(|buffer_id| {
-                        outline_panel.update(&mut cx, |outline_panel, cx| {
+                        outline_panel.update(cx, |outline_panel, cx| {
                             outline_panel
                                 .collapsed_entries
                                 .remove(&CollapsedEntry::ExternalFile(buffer_id));
@@ -1999,7 +1999,7 @@ impl OutlinePanel {
                 _ => return anyhow::Ok(()),
             };
             if let Some((worktree, buffer_entry)) = related_buffer_entry {
-                outline_panel.update(&mut cx, |outline_panel, cx| {
+                outline_panel.update(cx, |outline_panel, cx| {
                     let worktree_id = worktree.read(cx).id();
                     let mut dirs_to_expand = Vec::new();
                     {
@@ -2039,7 +2039,7 @@ impl OutlinePanel {
                 })?
             }
 
-            outline_panel.update_in(&mut cx, |outline_panel, window, cx| {
+            outline_panel.update_in(cx, |outline_panel, window, cx| {
                 outline_panel.select_entry(entry_with_selection, false, window, cx);
                 outline_panel.update_cached_entries(None, window, cx);
             })?;
@@ -2556,7 +2556,7 @@ impl OutlinePanel {
         let active_multi_buffer = active_editor.read(cx).buffer().clone();
         let new_entries = self.new_entries_for_fs_update.clone();
         self.updating_fs_entries = true;
-        self.fs_entries_update_task = cx.spawn_in(window, |outline_panel, mut cx| async move {
+        self.fs_entries_update_task = cx.spawn_in(window, async move |outline_panel, cx| {
             if let Some(debounce) = debounce {
                 cx.background_executor().timer(debounce).await;
             }
@@ -2565,7 +2565,7 @@ impl OutlinePanel {
             let mut new_unfolded_dirs = HashMap::default();
             let mut root_entries = HashSet::default();
             let mut new_excerpts = HashMap::<BufferId, HashMap<ExcerptId, Excerpt>>::default();
-            let Ok(buffer_excerpts) = outline_panel.update(&mut cx, |outline_panel, cx| {
+            let Ok(buffer_excerpts) = outline_panel.update(cx, |outline_panel, cx| {
                 new_collapsed_entries = outline_panel.collapsed_entries.clone();
                 new_unfolded_dirs = outline_panel.unfolded_dirs.clone();
                 let multi_buffer_snapshot = active_multi_buffer.read(cx).snapshot(cx);
@@ -2898,7 +2898,7 @@ impl OutlinePanel {
             };
 
             outline_panel
-                .update_in(&mut cx, |outline_panel, window, cx| {
+                .update_in(cx, |outline_panel, window, cx| {
                     outline_panel.updating_fs_entries = false;
                     outline_panel.new_entries_for_fs_update.clear();
                     outline_panel.excerpts = new_excerpts;
@@ -3211,7 +3211,7 @@ impl OutlinePanel {
                 let first_update = first_update.clone();
                 self.outline_fetch_tasks.insert(
                     (buffer_id, excerpt_id),
-                    cx.spawn_in(window, |outline_panel, mut cx| async move {
+                    cx.spawn_in(window, async move |outline_panel, cx| {
                         let fetched_outlines = cx
                             .background_spawn(async move {
                                 buffer_snapshot
@@ -3224,7 +3224,7 @@ impl OutlinePanel {
                             })
                             .await;
                         outline_panel
-                            .update_in(&mut cx, |outline_panel, window, cx| {
+                            .update_in(cx, |outline_panel, window, cx| {
                                 if let Some(excerpt) = outline_panel
                                     .excerpts
                                     .entry(buffer_id)
@@ -3396,12 +3396,12 @@ impl OutlinePanel {
         let is_singleton = self.is_singleton_active(cx);
         let query = self.query(cx);
         self.updating_cached_entries = true;
-        self.cached_entries_update_task = cx.spawn_in(window, |outline_panel, mut cx| async move {
+        self.cached_entries_update_task = cx.spawn_in(window, async move |outline_panel, cx| {
             if let Some(debounce) = debounce {
                 cx.background_executor().timer(debounce).await;
             }
             let Some(new_cached_entries) = outline_panel
-                .update_in(&mut cx, |outline_panel, window, cx| {
+                .update_in(cx, |outline_panel, window, cx| {
                     outline_panel.generate_cached_entries(is_singleton, query, window, cx)
                 })
                 .ok()
@@ -3410,7 +3410,7 @@ impl OutlinePanel {
             };
             let (new_cached_entries, max_width_item_index) = new_cached_entries.await;
             outline_panel
-                .update_in(&mut cx, |outline_panel, window, cx| {
+                .update_in(cx, |outline_panel, window, cx| {
                     outline_panel.cached_entries = new_cached_entries;
                     outline_panel.max_width_item_index = max_width_item_index;
                     if outline_panel.selected_entry.is_invalidated()
@@ -3448,10 +3448,10 @@ impl OutlinePanel {
         let Some(active_editor) = self.active_editor() else {
             return Task::ready((Vec::new(), None));
         };
-        cx.spawn_in(window, |outline_panel, mut cx| async move {
+        cx.spawn_in(window, async move |outline_panel, cx| {
             let mut generation_state = GenerationState::default();
 
-            let Ok(()) = outline_panel.update(&mut cx, |outline_panel, cx| {
+            let Ok(()) = outline_panel.update(cx, |outline_panel, cx| {
                 let auto_fold_dirs = OutlinePanelSettings::get_global(cx).auto_fold_dirs;
                 let mut folded_dirs_entry = None::<(usize, FoldedDirsEntry)>;
                 let track_matches = query.is_some();
@@ -4380,12 +4380,12 @@ impl OutlinePanel {
         if !Self::should_autohide_scrollbar(cx) {
             return;
         }
-        self.hide_scrollbar_task = Some(cx.spawn_in(window, |panel, mut cx| async move {
+        self.hide_scrollbar_task = Some(cx.spawn_in(window, async move |panel, cx| {
             cx.background_executor()
                 .timer(SCROLLBAR_SHOW_INTERVAL)
                 .await;
             panel
-                .update(&mut cx, |panel, cx| {
+                .update(cx, |panel, cx| {
                     panel.show_scrollbar = false;
                     cx.notify();
                 })
@@ -4811,9 +4811,9 @@ impl Panel for OutlinePanel {
     }
 
     fn set_active(&mut self, active: bool, window: &mut Window, cx: &mut Context<Self>) {
-        cx.spawn_in(window, |outline_panel, mut cx| async move {
+        cx.spawn_in(window, async move |outline_panel, cx| {
             outline_panel
-                .update_in(&mut cx, |outline_panel, window, cx| {
+                .update_in(cx, |outline_panel, window, cx| {
                     let old_active = outline_panel.active;
                     outline_panel.active = active;
                     if old_active != active {
@@ -6512,7 +6512,11 @@ outline: struct OutlineEntryExcerpt
         let window = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
 
         let outline_panel = window
-            .update(cx, |_, window, cx| cx.spawn_in(window, OutlinePanel::load))
+            .update(cx, |_, window, cx| {
+                cx.spawn_in(window, async |this, cx| {
+                    OutlinePanel::load(this, cx.clone()).await
+                })
+            })
             .unwrap()
             .await
             .expect("Failed to load outline panel");

crates/picker/src/picker.rs 🔗

@@ -578,8 +578,8 @@ impl<D: PickerDelegate> Picker<D> {
         // asynchronously.
         self.pending_update_matches = Some(PendingUpdateMatches {
             delegate_update_matches: Some(delegate_pending_update_matches),
-            _task: cx.spawn_in(window, |this, mut cx| async move {
-                let delegate_pending_update_matches = this.update(&mut cx, |this, _| {
+            _task: cx.spawn_in(window, async move |this, cx| {
+                let delegate_pending_update_matches = this.update(cx, |this, _| {
                     this.pending_update_matches
                         .as_mut()
                         .unwrap()
@@ -588,7 +588,7 @@ impl<D: PickerDelegate> Picker<D> {
                         .unwrap()
                 })?;
                 delegate_pending_update_matches.await;
-                this.update_in(&mut cx, |this, window, cx| {
+                this.update_in(cx, |this, window, cx| {
                     this.matches_updated(window, cx);
                 })
             }),
@@ -724,12 +724,12 @@ impl<D: PickerDelegate> Picker<D> {
 
     fn hide_scrollbar(&mut self, cx: &mut Context<Self>) {
         const SCROLLBAR_SHOW_INTERVAL: Duration = Duration::from_secs(1);
-        self.hide_scrollbar_task = Some(cx.spawn(|panel, mut cx| async move {
+        self.hide_scrollbar_task = Some(cx.spawn(async move |panel, cx| {
             cx.background_executor()
                 .timer(SCROLLBAR_SHOW_INTERVAL)
                 .await;
             panel
-                .update(&mut cx, |panel, cx| {
+                .update(cx, |panel, cx| {
                     panel.scrollbar_visibility = false;
                     cx.notify();
                 })

crates/prettier/src/prettier.rs 🔗

@@ -248,7 +248,7 @@ impl Prettier {
         server_id: LanguageServerId,
         prettier_dir: PathBuf,
         node: NodeRuntime,
-        cx: AsyncApp,
+        mut cx: AsyncApp,
     ) -> anyhow::Result<Self> {
         use lsp::{LanguageServerBinary, LanguageServerName};
 
@@ -280,7 +280,7 @@ impl Prettier {
             &prettier_dir,
             None,
             Default::default(),
-            cx.clone(),
+            &mut cx,
         )
         .context("prettier server creation")?;
 

crates/project/src/buffer_store.rs 🔗

@@ -111,9 +111,9 @@ impl RemoteBufferStore {
         let (tx, rx) = oneshot::channel();
         self.remote_buffer_listeners.entry(id).or_default().push(tx);
 
-        cx.spawn(|this, cx| async move {
+        cx.spawn(async move |this, cx| {
             if let Some(buffer) = this
-                .read_with(&cx, |buffer_store, _| buffer_store.get(id))
+                .read_with(cx, |buffer_store, _| buffer_store.get(id))
                 .ok()
                 .flatten()
             {
@@ -135,7 +135,7 @@ impl RemoteBufferStore {
         let version = buffer.version();
         let rpc = self.upstream_client.clone();
         let project_id = self.project_id;
-        cx.spawn(move |_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             let response = rpc
                 .request(proto::SaveBuffer {
                     project_id,
@@ -147,7 +147,7 @@ impl RemoteBufferStore {
             let version = deserialize_version(&response.version);
             let mtime = response.mtime.map(|mtime| mtime.into());
 
-            buffer_handle.update(&mut cx, |buffer, cx| {
+            buffer_handle.update(cx, |buffer, cx| {
                 buffer.did_save(version.clone(), mtime, cx);
             })?;
 
@@ -263,15 +263,13 @@ impl RemoteBufferStore {
         push_to_history: bool,
         cx: &mut Context<BufferStore>,
     ) -> Task<Result<ProjectTransaction>> {
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let mut project_transaction = ProjectTransaction::default();
             for (buffer_id, transaction) in message.buffer_ids.into_iter().zip(message.transactions)
             {
                 let buffer_id = BufferId::new(buffer_id)?;
                 let buffer = this
-                    .update(&mut cx, |this, cx| {
-                        this.wait_for_remote_buffer(buffer_id, cx)
-                    })?
+                    .update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
                     .await?;
                 let transaction = language::proto::deserialize_transaction(transaction)?;
                 project_transaction.0.insert(buffer, transaction);
@@ -279,13 +277,13 @@ impl RemoteBufferStore {
 
             for (buffer, transaction) in &project_transaction.0 {
                 buffer
-                    .update(&mut cx, |buffer, _| {
+                    .update(cx, |buffer, _| {
                         buffer.wait_for_edits(transaction.edit_ids.iter().copied())
                     })?
                     .await?;
 
                 if push_to_history {
-                    buffer.update(&mut cx, |buffer, _| {
+                    buffer.update(cx, |buffer, _| {
                         buffer.push_transaction(transaction.clone(), Instant::now());
                     })?;
                 }
@@ -304,7 +302,7 @@ impl RemoteBufferStore {
         let worktree_id = worktree.read(cx).id().to_proto();
         let project_id = self.project_id;
         let client = self.upstream_client.clone();
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = client
                 .request(proto::OpenBufferByPath {
                     project_id,
@@ -315,7 +313,7 @@ impl RemoteBufferStore {
             let buffer_id = BufferId::new(response.buffer_id)?;
 
             let buffer = this
-                .update(&mut cx, {
+                .update(cx, {
                     |this, cx| this.wait_for_remote_buffer(buffer_id, cx)
                 })?
                 .await?;
@@ -328,14 +326,12 @@ impl RemoteBufferStore {
         let create = self.upstream_client.request(proto::OpenNewBuffer {
             project_id: self.project_id,
         });
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = create.await?;
             let buffer_id = BufferId::new(response.buffer_id)?;
 
-            this.update(&mut cx, |this, cx| {
-                this.wait_for_remote_buffer(buffer_id, cx)
-            })?
-            .await
+            this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
+                .await
         })
     }
 
@@ -353,12 +349,12 @@ impl RemoteBufferStore {
                 .collect(),
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = request
                 .await?
                 .transaction
                 .ok_or_else(|| anyhow!("missing transaction"))?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.deserialize_project_transaction(response, push_to_history, cx)
             })?
             .await
@@ -392,10 +388,10 @@ impl LocalBufferStore {
             worktree.write_file(path.as_ref(), text, line_ending, cx)
         });
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let new_file = save.await?;
             let mtime = new_file.disk_state().mtime();
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 if let Some((downstream_client, project_id)) = this.downstream_client.clone() {
                     if has_changed_file {
                         downstream_client
@@ -416,7 +412,7 @@ impl LocalBufferStore {
                         .log_err();
                 }
             })?;
-            buffer_handle.update(&mut cx, |buffer, cx| {
+            buffer_handle.update(cx, |buffer, cx| {
                 if has_changed_file {
                     buffer.file_updated(new_file, cx);
                 }
@@ -654,7 +650,7 @@ impl LocalBufferStore {
             let load_file = worktree.load_file(path.as_ref(), cx);
             let reservation = cx.reserve_entity();
             let buffer_id = BufferId::from(reservation.entity_id().as_non_zero_u64());
-            cx.spawn(move |_, mut cx| async move {
+            cx.spawn(async move |_, cx| {
                 let loaded = load_file.await?;
                 let text_buffer = cx
                     .background_spawn(async move { text::Buffer::new(0, buffer_id, loaded.text) })
@@ -665,7 +661,7 @@ impl LocalBufferStore {
             })
         });
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let buffer = match load_buffer.await {
                 Ok(buffer) => Ok(buffer),
                 Err(error) if is_not_found_error(&error) => cx.new(|cx| {
@@ -686,7 +682,7 @@ impl LocalBufferStore {
                 }),
                 Err(e) => Err(e),
             }?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.add_buffer(buffer.clone(), cx)?;
                 let buffer_id = buffer.read(cx).remote_id();
                 if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
@@ -713,10 +709,10 @@ impl LocalBufferStore {
     }
 
     fn create_buffer(&self, cx: &mut Context<BufferStore>) -> Task<Result<Entity<Buffer>>> {
-        cx.spawn(|buffer_store, mut cx| async move {
+        cx.spawn(async move |buffer_store, cx| {
             let buffer =
                 cx.new(|cx| Buffer::local("", cx).with_language(language::PLAIN_TEXT.clone(), cx))?;
-            buffer_store.update(&mut cx, |buffer_store, cx| {
+            buffer_store.update(cx, |buffer_store, cx| {
                 buffer_store.add_buffer(buffer.clone(), cx).log_err();
             })?;
             Ok(buffer)
@@ -729,13 +725,11 @@ impl LocalBufferStore {
         push_to_history: bool,
         cx: &mut Context<BufferStore>,
     ) -> Task<Result<ProjectTransaction>> {
-        cx.spawn(move |_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             let mut project_transaction = ProjectTransaction::default();
             for buffer in buffers {
-                let transaction = buffer
-                    .update(&mut cx, |buffer, cx| buffer.reload(cx))?
-                    .await?;
-                buffer.update(&mut cx, |buffer, cx| {
+                let transaction = buffer.update(cx, |buffer, cx| buffer.reload(cx))?.await?;
+                buffer.update(cx, |buffer, cx| {
                     if let Some(transaction) = transaction {
                         if !push_to_history {
                             buffer.forget_transaction(transaction.id);
@@ -866,9 +860,9 @@ impl BufferStore {
 
                 entry
                     .insert(
-                        cx.spawn(move |this, mut cx| async move {
+                        cx.spawn(async move |this, cx| {
                             let load_result = load_buffer.await;
-                            this.update(&mut cx, |this, cx| {
+                            this.update(cx, |this, cx| {
                                 // Record the fact that the buffer is no longer loading.
                                 this.loading_buffers.remove(&project_path);
 
@@ -936,9 +930,9 @@ impl BufferStore {
                 this.save_remote_buffer(buffer.clone(), Some(path.to_proto()), cx)
             }
         };
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             task.await?;
-            this.update(&mut cx, |_, cx| {
+            this.update(cx, |_, cx| {
                 cx.emit(BufferStoreEvent::BufferChangedFilePath { buffer, old_file });
             })
         })
@@ -978,7 +972,7 @@ impl BufferStore {
                     anyhow::Ok(Some((repo, relative_path, content)))
                 });
 
-                cx.spawn(|cx| async move {
+                cx.spawn(async move |cx| {
                     let Some((repo, relative_path, content)) = blame_params? else {
                         return Ok(None);
                     };
@@ -993,7 +987,7 @@ impl BufferStore {
                 let version = buffer.version();
                 let project_id = worktree.project_id();
                 let client = worktree.client();
-                cx.spawn(|_| async move {
+                cx.spawn(async move |_| {
                     let response = client
                         .request(proto::BlameBuffer {
                             project_id,
@@ -1038,7 +1032,7 @@ impl BufferStore {
                         return Task::ready(Err(anyhow!("no permalink available")));
                     }
                     let file_path = worktree_path.join(file.path());
-                    return cx.spawn(|cx| async move {
+                    return cx.spawn(async move |cx| {
                         let provider_registry =
                             cx.update(GitHostingProviderRegistry::default_global)?;
                         get_permalink_in_rust_registry_src(provider_registry, file_path, selection)
@@ -1058,7 +1052,7 @@ impl BufferStore {
                     .unwrap_or("origin")
                     .to_string();
 
-                cx.spawn(|cx| async move {
+                cx.spawn(async move |cx| {
                     let origin_url = repo
                         .remote_url(&remote)
                         .ok_or_else(|| anyhow!("remote \"{remote}\" not found"))?;
@@ -1092,7 +1086,7 @@ impl BufferStore {
                 let buffer_id = buffer.remote_id();
                 let project_id = worktree.project_id();
                 let client = worktree.client();
-                cx.spawn(|_| async move {
+                cx.spawn(async move |_| {
                     let response = client
                         .request(proto::GetPermalinkToLine {
                             project_id,
@@ -1281,14 +1275,14 @@ impl BufferStore {
             })
             .chunks(MAX_CONCURRENT_BUFFER_OPENS);
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             for buffer in unnamed_buffers {
                 tx.send(buffer).await.ok();
             }
 
             let mut project_paths_rx = pin!(project_paths_rx);
             while let Some(project_paths) = project_paths_rx.next().await {
-                let buffers = this.update(&mut cx, |this, cx| {
+                let buffers = this.update(cx, |this, cx| {
                     project_paths
                         .into_iter()
                         .map(|project_path| this.open_buffer(project_path, cx))
@@ -1776,14 +1770,14 @@ impl BufferStore {
             return Task::ready(Ok(()));
         };
 
-        cx.spawn(|this, mut cx| async move {
-            let Some(buffer) = this.update(&mut cx, |this, _| this.get(buffer_id))? else {
+        cx.spawn(async move |this, cx| {
+            let Some(buffer) = this.update(cx, |this, _| this.get(buffer_id))? else {
                 return anyhow::Ok(());
             };
 
-            let operations = buffer.update(&mut cx, |b, cx| b.serialize_ops(None, cx))?;
+            let operations = buffer.update(cx, |b, cx| b.serialize_ops(None, cx))?;
             let operations = operations.await;
-            let state = buffer.update(&mut cx, |buffer, cx| buffer.to_proto(cx))?;
+            let state = buffer.update(cx, |buffer, cx| buffer.to_proto(cx))?;
 
             let initial_state = proto::CreateBufferForPeer {
                 project_id,

crates/project/src/connection_manager.rs 🔗

@@ -7,7 +7,7 @@ use gpui::{App, AppContext as _, AsyncApp, Context, Entity, Global, Task, WeakEn
 use postage::stream::Stream;
 use rpc::proto;
 use std::{sync::Arc, time::Duration};
-use util::{ResultExt, TryFutureExt};
+use util::ResultExt;
 
 impl Global for GlobalManager {}
 struct GlobalManager(Entity<Manager>);
@@ -65,7 +65,11 @@ impl Manager {
         if self.maintain_connection.is_none() {
             self.maintain_connection = Some(cx.spawn({
                 let client = self.client.clone();
-                move |_, cx| Self::maintain_connection(manager, client.clone(), cx).log_err()
+                async move |_, cx| {
+                    Self::maintain_connection(manager, client.clone(), cx)
+                        .await
+                        .log_err()
+                }
             }));
         }
     }
@@ -102,11 +106,11 @@ impl Manager {
                 .collect(),
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = request.await?;
             let message_id = response.message_id;
 
-            this.update(&mut cx, |_, cx| {
+            this.update(cx, |_, cx| {
                 for rejoined_project in response.payload.rejoined_projects {
                     if let Some(project) = projects.get(&rejoined_project.id) {
                         project.update(cx, |project, cx| {
@@ -133,7 +137,7 @@ impl Manager {
     async fn maintain_connection(
         this: WeakEntity<Self>,
         client: Arc<Client>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<()> {
         let mut client_status = client.status();
         loop {
@@ -155,7 +159,7 @@ impl Manager {
                                 log::info!("client reconnected, attempting to rejoin projects");
 
                                 let Some(this) = this.upgrade() else { break };
-                                match this.update(&mut cx, |this, cx| this.reconnected(cx)) {
+                                match this.update(cx, |this, cx| this.reconnected(cx)) {
                                     Ok(task) => {
                                         if task.await.log_err().is_some() {
                                             return true;
@@ -204,7 +208,7 @@ impl Manager {
         // we leave the room and return an error.
         if let Some(this) = this.upgrade() {
             log::info!("reconnection failed, disconnecting projects");
-            this.update(&mut cx, |this, cx| this.connection_lost(cx))?;
+            this.update(cx, |this, cx| this.connection_lost(cx))?;
         }
 
         Ok(())

crates/project/src/debounced_delay.rs 🔗

@@ -35,7 +35,7 @@ impl<E: 'static> DebouncedDelay<E> {
         self.cancel_channel = Some(sender);
 
         let previous_task = self.task.take();
-        self.task = Some(cx.spawn(move |entity, mut cx| async move {
+        self.task = Some(cx.spawn(async move |entity, cx| {
             let mut timer = cx.background_executor().timer(delay).fuse();
             if let Some(previous_task) = previous_task {
                 previous_task.await;
@@ -46,7 +46,7 @@ impl<E: 'static> DebouncedDelay<E> {
                 _ = timer => {}
             }
 
-            if let Ok(task) = entity.update(&mut cx, |project, cx| (func)(project, cx)) {
+            if let Ok(task) = entity.update(cx, |project, cx| (func)(project, cx)) {
                 task.await;
             }
         }));

crates/project/src/debugger/breakpoint_store.rs 🔗

@@ -448,7 +448,7 @@ impl BreakpointStore {
     ) -> Task<Result<()>> {
         if let BreakpointStoreMode::Local(mode) = &self.mode {
             let mode = mode.clone();
-            cx.spawn(move |this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 let mut new_breakpoints = BTreeMap::default();
                 for (path, bps) in breakpoints {
                     if bps.is_empty() {
@@ -456,13 +456,13 @@ impl BreakpointStore {
                     }
                     let (worktree, relative_path) = mode
                         .worktree_store
-                        .update(&mut cx, |this, cx| {
+                        .update(cx, |this, cx| {
                             this.find_or_create_worktree(&path, false, cx)
                         })?
                         .await?;
                     let buffer = mode
                         .buffer_store
-                        .update(&mut cx, |this, cx| {
+                        .update(cx, |this, cx| {
                             let path = ProjectPath {
                                 worktree_id: worktree.read(cx).id(),
                                 path: relative_path.into(),
@@ -474,10 +474,10 @@ impl BreakpointStore {
                         log::error!("Todo: Serialized breakpoints which do not have buffer (yet)");
                         continue;
                     };
-                    let snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
+                    let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot())?;
 
                     let mut breakpoints_for_file =
-                        this.update(&mut cx, |_, cx| BreakpointsInFile::new(buffer, cx))?;
+                        this.update(cx, |_, cx| BreakpointsInFile::new(buffer, cx))?;
 
                     for bp in bps {
                         let position = snapshot.anchor_before(PointUtf16::new(bp.position, 0));
@@ -487,7 +487,7 @@ impl BreakpointStore {
                     }
                     new_breakpoints.insert(path, breakpoints_for_file);
                 }
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.breakpoints = new_breakpoints;
                     cx.notify();
                 })?;

crates/project/src/debugger/dap_store.rs 🔗

@@ -149,12 +149,12 @@ impl DapStore {
         let (start_debugging_tx, mut message_rx) =
             futures::channel::mpsc::unbounded::<(SessionId, Message)>();
 
-        let _start_debugging_task = cx.spawn(move |this, mut cx| async move {
+        let _start_debugging_task = cx.spawn(async move |this, cx| {
             while let Some((session_id, message)) = message_rx.next().await {
                 match message {
                     Message::Request(request) => {
                         let _ = this
-                            .update(&mut cx, |this, cx| {
+                            .update(cx, |this, cx| {
                                 if request.command == StartDebugging::COMMAND {
                                     this.handle_start_debugging_request(session_id, request, cx)
                                         .detach_and_log_err(cx);
@@ -361,11 +361,11 @@ impl DapStore {
             cx,
         );
 
-        let task = cx.spawn(|this, mut cx| async move {
+        let task = cx.spawn(async move |this, cx| {
             let session = match start_client_task.await {
                 Ok(session) => session,
                 Err(error) => {
-                    this.update(&mut cx, |_, cx| {
+                    this.update(cx, |_, cx| {
                         cx.emit(DapStoreEvent::Notification(error.to_string()));
                     })
                     .log_err();
@@ -376,21 +376,21 @@ impl DapStore {
 
             // we have to insert the session early, so we can handle reverse requests
             // that need the session to be available
-            this.update(&mut cx, |store, cx| {
+            this.update(cx, |store, cx| {
                 store.sessions.insert(session_id, session.clone());
                 cx.emit(DapStoreEvent::DebugClientStarted(session_id));
                 cx.notify();
             })?;
 
             match session
-                .update(&mut cx, |session, cx| {
+                .update(cx, |session, cx| {
                     session.initialize_sequence(initialized_rx, cx)
                 })?
                 .await
             {
                 Ok(_) => {}
                 Err(error) => {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         cx.emit(DapStoreEvent::Notification(error.to_string()));
 
                         this.shutdown_session(session_id, cx)
@@ -456,7 +456,7 @@ impl DapStore {
         );
 
         let request_seq = request.seq;
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             let (success, body) = match new_session_task.await {
                 Ok(_) => (true, None),
                 Err(error) => (
@@ -476,7 +476,7 @@ impl DapStore {
             };
 
             parent_session
-                .update(&mut cx, |session, cx| {
+                .update(cx, |session, cx| {
                     session.respond_to_client(
                         request_seq,
                         success,
@@ -572,7 +572,7 @@ impl DapStore {
         cx.notify();
 
         let session = session.downgrade();
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             let (success, body) = match rx.next().await {
                 Some(Ok(pid)) => (
                     true,
@@ -615,7 +615,7 @@ impl DapStore {
             };
 
             session
-                .update(&mut cx, |session, cx| {
+                .update(cx, |session, cx| {
                     session.respond_to_client(
                         seq,
                         success,

crates/project/src/debugger/session.rs 🔗

@@ -191,8 +191,8 @@ impl LocalMode {
         messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
         cx: AsyncApp,
     ) -> Task<Result<(Self, Capabilities)>> {
-        cx.spawn(move |mut cx| async move {
-            let (adapter, binary) = Self::get_adapter_binary(&config, &delegate, &mut cx).await?;
+        cx.spawn(async move |cx| {
+            let (adapter, binary) = Self::get_adapter_binary(&config, &delegate,  cx).await?;
 
             let message_handler = Box::new(move |message| {
                 messages_tx.unbounded_send(message).ok();
@@ -439,7 +439,7 @@ impl LocalMode {
 
         let configuration_sequence = cx.spawn({
             let this = self.clone();
-            move |cx| async move {
+            async move |cx| {
                 initialized_rx.await?;
                 // todo(debugger) figure out if we want to handle a breakpoint response error
                 // This will probably consist of letting a user know that breakpoints failed to be set
@@ -697,7 +697,7 @@ impl Session {
     ) -> Task<Result<Entity<Self>>> {
         let (message_tx, mut message_rx) = futures::channel::mpsc::unbounded();
 
-        cx.spawn(move |mut cx| async move {
+        cx.spawn(async move |cx| {
             let (mode, capabilities) = LocalMode::new(
                 session_id,
                 parent_session.clone(),
@@ -710,31 +710,30 @@ impl Session {
             .await?;
 
             cx.new(|cx| {
-                let _background_tasks =
-                    vec![cx.spawn(move |this: WeakEntity<Self>, mut cx| async move {
-                        let mut initialized_tx = Some(initialized_tx);
-                        while let Some(message) = message_rx.next().await {
-                            if let Message::Event(event) = message {
-                                if let Events::Initialized(_) = *event {
-                                    if let Some(tx) = initialized_tx.take() {
-                                        tx.send(()).ok();
-                                    }
-                                } else {
-                                    let Ok(_) = this.update(&mut cx, |session, cx| {
-                                        session.handle_dap_event(event, cx);
-                                    }) else {
-                                        break;
-                                    };
+                let _background_tasks = vec![cx.spawn(async move |this: WeakEntity<Self>, cx| {
+                    let mut initialized_tx = Some(initialized_tx);
+                    while let Some(message) = message_rx.next().await {
+                        if let Message::Event(event) = message {
+                            if let Events::Initialized(_) = *event {
+                                if let Some(tx) = initialized_tx.take() {
+                                    tx.send(()).ok();
                                 }
                             } else {
-                                let Ok(_) = start_debugging_requests_tx
-                                    .unbounded_send((session_id, message))
-                                else {
+                                let Ok(_) = this.update(cx, |session, cx| {
+                                    session.handle_dap_event(event, cx);
+                                }) else {
                                     break;
                                 };
                             }
+                        } else {
+                            let Ok(_) =
+                                start_debugging_requests_tx.unbounded_send((session_id, message))
+                            else {
+                                break;
+                            };
                         }
-                    })];
+                    }
+                })];
 
                 cx.subscribe(&breakpoint_store, |this, _, event, cx| match event {
                     BreakpointStoreEvent::BreakpointsUpdated(path, reason) => {
@@ -1102,17 +1101,17 @@ impl Session {
             let error = Err(anyhow::Error::msg(
                 "Couldn't complete request because it's not supported",
             ));
-            return cx.spawn(|this, mut cx| async move {
-                this.update(&mut cx, |this, cx| process_result(this, error, cx))
+            return cx.spawn(async move |this, cx| {
+                this.update(cx, |this, cx| process_result(this, error, cx))
                     .log_err()
                     .flatten()
             });
         }
 
         let request = mode.request_dap(session_id, request, cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = request.await;
-            this.update(&mut cx, |this, cx| process_result(this, result, cx))
+            this.update(cx, |this, cx| process_result(this, result, cx))
                 .log_err()
                 .flatten()
         })

crates/project/src/environment.rs 🔗

@@ -97,7 +97,7 @@ impl ProjectEnvironment {
 
         if let Some(cli_environment) = self.get_cli_environment() {
             return cx
-                .spawn(|_, _| async move {
+                .spawn(async move |_, _| {
                     let path = cli_environment
                         .get("PATH")
                         .map(|path| path.as_str())
@@ -144,7 +144,7 @@ impl ProjectEnvironment {
     ) -> Task<Option<HashMap<String, String>>> {
         let load_direnv = ProjectSettings::get_global(cx).load_direnv.clone();
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let (mut shell_env, error_message) = cx
                 .background_spawn({
                     let worktree_abs_path = worktree_abs_path.clone();
@@ -169,7 +169,7 @@ impl ProjectEnvironment {
             }
 
             if let Some(error) = error_message {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.environment_error_messages.insert(worktree_id, error);
                     cx.emit(ProjectEnvironmentEvent::ErrorsUpdated)
                 })

crates/project/src/git.rs 🔗

@@ -351,7 +351,7 @@ impl GitStore {
                 let staged_text = self.state.load_staged_text(&buffer, &self.buffer_store, cx);
                 entry
                     .insert(
-                        cx.spawn(move |this, cx| async move {
+                        cx.spawn(async move |this, cx| {
                             Self::open_diff_internal(
                                 this,
                                 DiffKind::Unstaged,
@@ -406,7 +406,7 @@ impl GitStore {
 
                 entry
                     .insert(
-                        cx.spawn(move |this, cx| async move {
+                        cx.spawn(async move |this, cx| {
                             Self::open_diff_internal(
                                 this,
                                 DiffKind::Uncommitted,
@@ -431,11 +431,11 @@ impl GitStore {
         kind: DiffKind,
         texts: Result<DiffBasesChange>,
         buffer_entity: Entity<Buffer>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<Entity<BufferDiff>> {
         let diff_bases_change = match texts {
             Err(e) => {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     let buffer = buffer_entity.read(cx);
                     let buffer_id = buffer.remote_id();
                     this.loading_diffs.remove(&(buffer_id, kind));
@@ -445,7 +445,7 @@ impl GitStore {
             Ok(change) => change,
         };
 
-        this.update(&mut cx, |this, cx| {
+        this.update(cx, |this, cx| {
             let buffer = buffer_entity.read(cx);
             let buffer_id = buffer.remote_id();
             let language = buffer.language().cloned();
@@ -736,13 +736,13 @@ impl GitStore {
                     )
                 });
                 let diff = diff.downgrade();
-                cx.spawn(|this, mut cx| async move {
+                cx.spawn(async move |this, cx| {
                     if let Ok(Err(error)) = cx.background_spawn(recv).await {
-                        diff.update(&mut cx, |diff, cx| {
+                        diff.update(cx, |diff, cx| {
                             diff.clear_pending_hunks(cx);
                         })
                         .ok();
-                        this.update(&mut cx, |_, cx| cx.emit(GitEvent::IndexWriteError(error)))
+                        this.update(cx, |_, cx| cx.emit(GitEvent::IndexWriteError(error)))
                             .ok();
                     }
                 })
@@ -973,7 +973,7 @@ impl GitStore {
     fn spawn_git_worker(cx: &mut Context<GitStore>) -> mpsc::UnboundedSender<GitJob> {
         let (job_tx, mut job_rx) = mpsc::unbounded::<GitJob>();
 
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             let mut jobs = VecDeque::new();
             loop {
                 while let Ok(Some(next_job)) = job_rx.try_next() {
@@ -989,7 +989,7 @@ impl GitStore {
                             continue;
                         }
                     }
-                    (job.job)(&mut cx).await;
+                    (job.job)(cx).await;
                 } else if let Some(job) = job_rx.next().await {
                     jobs.push_back(job);
                 } else {
@@ -1772,7 +1772,7 @@ impl BufferDiffState {
             (None, None) => true,
             _ => false,
         };
-        self.recalculate_diff_task = Some(cx.spawn(|this, mut cx| async move {
+        self.recalculate_diff_task = Some(cx.spawn(async move |this, cx| {
             let mut new_unstaged_diff = None;
             if let Some(unstaged_diff) = &unstaged_diff {
                 new_unstaged_diff = Some(
@@ -1784,7 +1784,7 @@ impl BufferDiffState {
                         language_changed,
                         language.clone(),
                         language_registry.clone(),
-                        &mut cx,
+                        cx,
                     )
                     .await?,
                 );
@@ -1804,7 +1804,7 @@ impl BufferDiffState {
                             language_changed,
                             language.clone(),
                             language_registry.clone(),
-                            &mut cx,
+                            cx,
                         )
                         .await?,
                     )
@@ -1814,7 +1814,7 @@ impl BufferDiffState {
             let unstaged_changed_range = if let Some((unstaged_diff, new_unstaged_diff)) =
                 unstaged_diff.as_ref().zip(new_unstaged_diff.clone())
             {
-                unstaged_diff.update(&mut cx, |diff, cx| {
+                unstaged_diff.update(cx, |diff, cx| {
                     diff.set_snapshot(&buffer, new_unstaged_diff, language_changed, None, cx)
                 })?
             } else {
@@ -1824,7 +1824,7 @@ impl BufferDiffState {
             if let Some((uncommitted_diff, new_uncommitted_diff)) =
                 uncommitted_diff.as_ref().zip(new_uncommitted_diff.clone())
             {
-                uncommitted_diff.update(&mut cx, |uncommitted_diff, cx| {
+                uncommitted_diff.update(cx, |uncommitted_diff, cx| {
                     uncommitted_diff.set_snapshot(
                         &buffer,
                         new_uncommitted_diff,
@@ -1836,7 +1836,7 @@ impl BufferDiffState {
             }
 
             if let Some(this) = this.upgrade() {
-                this.update(&mut cx, |this, _| {
+                this.update(cx, |this, _| {
                     this.index_changed = false;
                     this.head_changed = false;
                     this.language_changed = false;
@@ -1873,7 +1873,7 @@ fn make_remote_delegate(
                 askpass_id,
                 prompt,
             });
-            cx.spawn(|_, _| async move {
+            cx.spawn(async move |_, _| {
                 tx.send(response.await?.response).ok();
                 anyhow::Ok(())
             })
@@ -2028,7 +2028,7 @@ impl Repository {
                 key,
                 job: Box::new(|cx: &mut AsyncApp| {
                     let job = job(git_repo, cx.clone());
-                    cx.spawn(|_| async move {
+                    cx.spawn(async move |_| {
                         let result = job.await;
                         result_tx.send(result).ok();
                     })
@@ -2150,7 +2150,7 @@ impl Repository {
         } = self.git_repo.clone()
         {
             let client = client.clone();
-            cx.spawn(|repository, mut cx| async move {
+            cx.spawn(async move |repository, cx| {
                 let request = client.request(proto::OpenCommitMessageBuffer {
                     project_id: project_id.0,
                     worktree_id: worktree_id.to_proto(),
@@ -2159,18 +2159,18 @@ impl Repository {
                 let response = request.await.context("requesting to open commit buffer")?;
                 let buffer_id = BufferId::new(response.buffer_id)?;
                 let buffer = buffer_store
-                    .update(&mut cx, |buffer_store, cx| {
+                    .update(cx, |buffer_store, cx| {
                         buffer_store.wait_for_remote_buffer(buffer_id, cx)
                     })?
                     .await?;
                 if let Some(language_registry) = languages {
                     let git_commit_language =
                         language_registry.language_for_name("Git Commit").await?;
-                    buffer.update(&mut cx, |buffer, cx| {
+                    buffer.update(cx, |buffer, cx| {
                         buffer.set_language(Some(git_commit_language), cx);
                     })?;
                 }
-                repository.update(&mut cx, |repository, _| {
+                repository.update(cx, |repository, _| {
                     repository.commit_message_buffer = Some(buffer.clone());
                 })?;
                 Ok(buffer)
@@ -2186,19 +2186,19 @@ impl Repository {
         buffer_store: Entity<BufferStore>,
         cx: &mut Context<Self>,
     ) -> Task<Result<Entity<Buffer>>> {
-        cx.spawn(|repository, mut cx| async move {
+        cx.spawn(async move |repository, cx| {
             let buffer = buffer_store
-                .update(&mut cx, |buffer_store, cx| buffer_store.create_buffer(cx))?
+                .update(cx, |buffer_store, cx| buffer_store.create_buffer(cx))?
                 .await?;
 
             if let Some(language_registry) = language_registry {
                 let git_commit_language = language_registry.language_for_name("Git Commit").await?;
-                buffer.update(&mut cx, |buffer, cx| {
+                buffer.update(cx, |buffer, cx| {
                     buffer.set_language(Some(git_commit_language), cx);
                 })?;
             }
 
-            repository.update(&mut cx, |repository, _| {
+            repository.update(cx, |repository, _| {
                 repository.commit_message_buffer = Some(buffer.clone());
             })?;
             Ok(buffer)
@@ -2347,13 +2347,13 @@ impl Repository {
             })
         }
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             for save_future in save_futures {
                 save_future.await?;
             }
             let env = env.await;
 
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 this.send_job(|git_repo, cx| async move {
                     match git_repo {
                         GitRepo::Local(repo) => repo.stage_paths(entries, env, cx).await,
@@ -2418,13 +2418,13 @@ impl Repository {
             })
         }
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             for save_future in save_futures {
                 save_future.await?;
             }
             let env = env.await;
 
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 this.send_job(|git_repo, cx| async move {
                     match git_repo {
                         GitRepo::Local(repo) => repo.unstage_paths(entries, env, cx).await,

crates/project/src/image_store.rs 🔗

@@ -191,14 +191,14 @@ impl ImageItem {
         let (tx, rx) = futures::channel::oneshot::channel();
 
         let content = local_file.load_bytes(cx);
-        self.reload_task = Some(cx.spawn(|this, mut cx| async move {
+        self.reload_task = Some(cx.spawn(async move |this, cx| {
             if let Some(image) = content
                 .await
                 .context("Failed to load image content")
                 .and_then(create_gpui_image)
                 .log_err()
             {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.image = image;
                     cx.emit(ImageItemEvent::Reloaded);
                 })
@@ -238,9 +238,9 @@ impl ProjectItem for ImageItem {
         // Only open the item if it's a binary image (no SVGs, etc.)
         // Since we do not have a way to toggle to an editor
         if Img::extensions().contains(&ext) && !ext.contains("svg") {
-            Some(cx.spawn(|mut cx| async move {
+            Some(cx.spawn(async move |cx| {
                 project
-                    .update(&mut cx, |project, cx| project.open_image(path, cx))?
+                    .update(cx, |project, cx| project.open_image(path, cx))?
                     .await
             }))
         } else {
@@ -389,9 +389,9 @@ impl ImageStore {
                     .state
                     .open_image(project_path.path.clone(), worktree, cx);
 
-                cx.spawn(move |this, mut cx| async move {
+                cx.spawn(async move |this, cx| {
                     let load_result = load_image.await;
-                    *tx.borrow_mut() = Some(this.update(&mut cx, |this, _cx| {
+                    *tx.borrow_mut() = Some(this.update(cx, |this, _cx| {
                         // Record the fact that the image is no longer loading.
                         this.loading_images_by_path.remove(&project_path);
                         let image = load_result.map_err(Arc::new)?;
@@ -480,7 +480,7 @@ impl ImageStoreImpl for Entity<LocalImageStore> {
         let load_file = worktree.update(cx, |worktree, cx| {
             worktree.load_binary_file(path.as_ref(), cx)
         });
-        cx.spawn(move |image_store, mut cx| async move {
+        cx.spawn(async move |image_store, cx| {
             let LoadedBinaryFile { file, content } = load_file.await?;
             let image = create_gpui_image(content)?;
 
@@ -494,7 +494,7 @@ impl ImageStoreImpl for Entity<LocalImageStore> {
 
             let image_id = cx.read_entity(&entity, |model, _| model.id)?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 image_store.update(cx, |image_store, cx| {
                     image_store.add_image(entity.clone(), cx)
                 })??;
@@ -522,9 +522,9 @@ impl ImageStoreImpl for Entity<LocalImageStore> {
         images: HashSet<Entity<ImageItem>>,
         cx: &mut Context<ImageStore>,
     ) -> Task<Result<()>> {
-        cx.spawn(move |_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             for image in images {
-                if let Some(rec) = image.update(&mut cx, |image, cx| image.reload(cx))? {
+                if let Some(rec) = image.update(cx, |image, cx| image.reload(cx))? {
                     rec.await?
                 }
             }

crates/project/src/lsp_command.rs 🔗

@@ -2957,14 +2957,14 @@ impl LspCommand for InlayHints {
             };
 
             let buffer = buffer.clone();
-            cx.spawn(move |mut cx| async move {
+            cx.spawn(async move |cx| {
                 InlayHints::lsp_to_project_hint(
                     lsp_hint,
                     &buffer,
                     server_id,
                     resolve_state,
                     force_no_type_left_padding,
-                    &mut cx,
+                    cx,
                 )
                 .await
             })

crates/project/src/lsp_store.rs 🔗

@@ -217,7 +217,7 @@ impl LocalLspStore {
             #[cfg(any(test, feature = "test-support"))]
             let lsp_store = self.weak.clone();
             let pending_workspace_folders = pending_workspace_folders.clone();
-            move |cx| async move {
+            async move |cx| {
                 let binary = binary.await?;
                 #[cfg(any(test, feature = "test-support"))]
                 if let Some(server) = lsp_store
@@ -226,7 +226,7 @@ impl LocalLspStore {
                             server_id,
                             &server_name,
                             binary.clone(),
-                            cx.to_async(),
+                            &mut cx.to_async(),
                         )
                     })
                     .ok()
@@ -256,93 +256,80 @@ impl LocalLspStore {
             let this = self.weak.clone();
             let pending_workspace_folders = pending_workspace_folders.clone();
             let fs = self.fs.clone();
-            cx.spawn(move |mut cx| async move {
-                let result = {
-                    let delegate = delegate.clone();
-                    let adapter = adapter.clone();
-                    let this = this.clone();
-                    let toolchains = this
-                        .update(&mut cx, |this, cx| this.toolchain_store(cx))
-                        .ok()?;
-                    let mut cx = cx.clone();
-                    async move {
-                        let language_server = pending_server.await?;
-
-                        let workspace_config = adapter
-                            .adapter
-                            .clone()
-                            .workspace_configuration(
-                                fs.as_ref(),
-                                &delegate,
-                                toolchains.clone(),
-                                &mut cx,
-                            )
-                            .await?;
+            cx.spawn(async move |cx| {
+                let result = async {
+                    let toolchains = this.update(cx, |this, cx| this.toolchain_store(cx))?;
+                    let language_server = pending_server.await?;
+
+                    let workspace_config = adapter
+                        .adapter
+                        .clone()
+                        .workspace_configuration(fs.as_ref(), &delegate, toolchains.clone(), cx)
+                        .await?;
 
-                        let mut initialization_options = adapter
-                            .adapter
-                            .clone()
-                            .initialization_options(fs.as_ref(), &(delegate))
-                            .await?;
+                    let mut initialization_options = adapter
+                        .adapter
+                        .clone()
+                        .initialization_options(fs.as_ref(), &(delegate))
+                        .await?;
 
-                        match (&mut initialization_options, override_options) {
-                            (Some(initialization_options), Some(override_options)) => {
-                                merge_json_value_into(override_options, initialization_options);
-                            }
-                            (None, override_options) => initialization_options = override_options,
-                            _ => {}
+                    match (&mut initialization_options, override_options) {
+                        (Some(initialization_options), Some(override_options)) => {
+                            merge_json_value_into(override_options, initialization_options);
                         }
+                        (None, override_options) => initialization_options = override_options,
+                        _ => {}
+                    }
 
-                        let initialization_params = cx.update(|cx| {
-                            let mut params = language_server.default_initialize_params(cx);
-                            params.initialization_options = initialization_options;
-                            adapter.adapter.prepare_initialize_params(params)
-                        })??;
+                    let initialization_params = cx.update(|cx| {
+                        let mut params = language_server.default_initialize_params(cx);
+                        params.initialization_options = initialization_options;
+                        adapter.adapter.prepare_initialize_params(params)
+                    })??;
 
-                        Self::setup_lsp_messages(
-                            this.clone(),
-                            fs,
-                            &language_server,
-                            delegate,
-                            adapter,
-                        );
-
-                        let did_change_configuration_params =
-                            Arc::new(lsp::DidChangeConfigurationParams {
-                                settings: workspace_config,
-                            });
-                        let language_server = cx
-                            .update(|cx| {
-                                language_server.initialize(
-                                    initialization_params,
-                                    did_change_configuration_params.clone(),
-                                    cx,
-                                )
-                            })?
-                            .await
-                            .inspect_err(|_| {
-                                if let Some(this) = this.upgrade() {
-                                    this.update(&mut cx, |_, cx| {
-                                        cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
-                                    })
-                                    .ok();
-                                }
-                            })?;
+                    Self::setup_lsp_messages(
+                        this.clone(),
+                        fs,
+                        &language_server,
+                        delegate.clone(),
+                        adapter.clone(),
+                    );
 
-                        language_server
-                            .notify::<lsp::notification::DidChangeConfiguration>(
-                                &did_change_configuration_params,
+                    let did_change_configuration_params =
+                        Arc::new(lsp::DidChangeConfigurationParams {
+                            settings: workspace_config,
+                        });
+                    let language_server = cx
+                        .update(|cx| {
+                            language_server.initialize(
+                                initialization_params,
+                                did_change_configuration_params.clone(),
+                                cx,
                             )
-                            .ok();
+                        })?
+                        .await
+                        .inspect_err(|_| {
+                            if let Some(this) = this.upgrade() {
+                                this.update(cx, |_, cx| {
+                                    cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
+                                })
+                                .ok();
+                            }
+                        })?;
 
-                        anyhow::Ok(language_server)
-                    }
+                    language_server
+                        .notify::<lsp::notification::DidChangeConfiguration>(
+                            &did_change_configuration_params,
+                        )
+                        .ok();
+
+                    anyhow::Ok(language_server)
                 }
                 .await;
 
                 match result {
                     Ok(server) => {
-                        this.update(&mut cx, |this, mut cx| {
+                        this.update(cx, |this, mut cx| {
                             this.insert_newly_running_language_server(
                                 adapter,
                                 server.clone(),
@@ -405,7 +392,7 @@ impl LocalLspStore {
 
         if settings.as_ref().is_some_and(|b| b.path.is_some()) {
             let settings = settings.unwrap();
-            return cx.spawn(|_| async move {
+            return cx.spawn(async move |_| {
                 Ok(LanguageServerBinary {
                     path: PathBuf::from(&settings.path.unwrap()),
                     env: Some(delegate.shell_env().await),
@@ -426,15 +413,10 @@ impl LocalLspStore {
             allow_binary_download,
         };
         let toolchains = self.toolchain_store.read(cx).as_language_toolchain_store();
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let binary_result = adapter
                 .clone()
-                .get_language_server_command(
-                    delegate.clone(),
-                    toolchains,
-                    lsp_binary_options,
-                    &mut cx,
-                )
+                .get_language_server_command(delegate.clone(), toolchains, lsp_binary_options, cx)
                 .await;
 
             delegate.update_status(adapter.name.clone(), BinaryStatus::None);
@@ -464,11 +446,11 @@ impl LocalLspStore {
             .on_notification::<lsp::notification::PublishDiagnostics, _>({
                 let adapter = adapter.clone();
                 let this = this.clone();
-                move |mut params, mut cx| {
+                move |mut params, cx| {
                     let adapter = adapter.clone();
                     if let Some(this) = this.upgrade() {
                         adapter.process_diagnostics(&mut params);
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             this.update_diagnostics(
                                 server_id,
                                 params,
@@ -488,11 +470,12 @@ impl LocalLspStore {
                 let delegate = delegate.clone();
                 let this = this.clone();
                 let fs = fs.clone();
-                move |params, mut cx| {
+                move |params, cx| {
                     let adapter = adapter.clone();
                     let delegate = delegate.clone();
                     let this = this.clone();
                     let fs = fs.clone();
+                    let mut cx = cx.clone();
                     async move {
                         let toolchains =
                             this.update(&mut cx, |this, cx| this.toolchain_store(cx))?;
@@ -521,8 +504,9 @@ impl LocalLspStore {
         language_server
             .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
                 let this = this.clone();
-                move |_, mut cx| {
+                move |_, cx| {
                     let this = this.clone();
+                    let mut cx = cx.clone();
                     async move {
                         let Some(server) =
                             this.update(&mut cx, |this, _| this.language_server_for_id(server_id))?
@@ -549,8 +533,9 @@ impl LocalLspStore {
         language_server
             .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
                 let this = this.clone();
-                move |params, mut cx| {
+                move |params, cx| {
                     let this = this.clone();
+                    let mut cx = cx.clone();
                     async move {
                         this.update(&mut cx, |this, _| {
                             if let Some(status) = this.language_server_statuses.get_mut(&server_id)
@@ -570,8 +555,9 @@ impl LocalLspStore {
         language_server
             .on_request::<lsp::request::RegisterCapability, _, _>({
                 let this = this.clone();
-                move |params, mut cx| {
+                move |params, cx| {
                     let this = this.clone();
+                    let mut cx = cx.clone();
                     async move {
                         for reg in params.registrations {
                             match reg.method.as_str() {
@@ -702,8 +688,9 @@ impl LocalLspStore {
         language_server
             .on_request::<lsp::request::UnregisterCapability, _, _>({
                 let this = this.clone();
-                move |params, mut cx| {
+                move |params, cx| {
                     let this = this.clone();
+                    let mut cx = cx.clone();
                     async move {
                         for unreg in params.unregisterations.iter() {
                             match unreg.method.as_str() {
@@ -775,13 +762,19 @@ impl LocalLspStore {
                 let adapter = adapter.clone();
                 let this = this.clone();
                 move |params, cx| {
-                    LocalLspStore::on_lsp_workspace_edit(
-                        this.clone(),
-                        params,
-                        server_id,
-                        adapter.clone(),
-                        cx,
-                    )
+                    let mut cx = cx.clone();
+                    let this = this.clone();
+                    let adapter = adapter.clone();
+                    async move {
+                        LocalLspStore::on_lsp_workspace_edit(
+                            this.clone(),
+                            params,
+                            server_id,
+                            adapter.clone(),
+                            &mut cx,
+                        )
+                        .await
+                    }
                 }
             })
             .detach();
@@ -789,8 +782,9 @@ impl LocalLspStore {
         language_server
             .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
                 let this = this.clone();
-                move |(), mut cx| {
+                move |(), cx| {
                     let this = this.clone();
+                    let mut cx = cx.clone();
                     async move {
                         this.update(&mut cx, |this, cx| {
                             cx.emit(LspStoreEvent::RefreshInlayHints);
@@ -810,8 +804,9 @@ impl LocalLspStore {
         language_server
             .on_request::<lsp::request::CodeLensRefresh, _, _>({
                 let this = this.clone();
-                move |(), mut cx| {
+                move |(), cx| {
                     let this = this.clone();
+                    let mut cx = cx.clone();
                     async move {
                         this.update(&mut cx, |this, cx| {
                             cx.emit(LspStoreEvent::RefreshCodeLens);
@@ -832,9 +827,10 @@ impl LocalLspStore {
             .on_request::<lsp::request::ShowMessageRequest, _, _>({
                 let this = this.clone();
                 let name = name.to_string();
-                move |params, mut cx| {
+                move |params, cx| {
                     let this = this.clone();
                     let name = name.to_string();
+                    let mut cx = cx.clone();
                     async move {
                         let actions = params.actions.unwrap_or_default();
                         let (tx, rx) = smol::channel::bounded(1);
@@ -869,9 +865,10 @@ impl LocalLspStore {
             .on_notification::<lsp::notification::ShowMessage, _>({
                 let this = this.clone();
                 let name = name.to_string();
-                move |params, mut cx| {
+                move |params, cx| {
                     let this = this.clone();
                     let name = name.to_string();
+                    let mut cx = cx.clone();
 
                     let (tx, _) = smol::channel::bounded(1);
                     let request = LanguageServerPromptRequest {
@@ -899,9 +896,9 @@ impl LocalLspStore {
         language_server
             .on_notification::<lsp::notification::Progress, _>({
                 let this = this.clone();
-                move |params, mut cx| {
+                move |params, cx| {
                     if let Some(this) = this.upgrade() {
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             this.on_lsp_progress(
                                 params,
                                 server_id,
@@ -918,9 +915,9 @@ impl LocalLspStore {
         language_server
             .on_notification::<lsp::notification::LogMessage, _>({
                 let this = this.clone();
-                move |params, mut cx| {
+                move |params, cx| {
                     if let Some(this) = this.upgrade() {
-                        this.update(&mut cx, |_, cx| {
+                        this.update(cx, |_, cx| {
                             cx.emit(LspStoreEvent::LanguageServerLog(
                                 server_id,
                                 LanguageServerLogType::Log(params.typ),
@@ -936,7 +933,8 @@ impl LocalLspStore {
         language_server
             .on_notification::<lsp::notification::LogTrace, _>({
                 let this = this.clone();
-                move |params, mut cx| {
+                move |params, cx| {
+                    let mut cx = cx.clone();
                     if let Some(this) = this.upgrade() {
                         this.update(&mut cx, |_, cx| {
                             cx.emit(LspStoreEvent::LanguageServerLog(
@@ -1077,11 +1075,11 @@ impl LocalLspStore {
         mut buffers: Vec<Entity<Buffer>>,
         kind: CodeActionKind,
         push_to_history: bool,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> anyhow::Result<ProjectTransaction> {
         // Do not allow multiple concurrent code actions requests for the
         // same buffer.
-        lsp_store.update(&mut cx, |this, cx| {
+        lsp_store.update(cx, |this, cx| {
             let this = this.as_local_mut().unwrap();
             buffers.retain(|buffer| {
                 this.buffers_being_formatted
@@ -1106,7 +1104,7 @@ impl LocalLspStore {
         let mut project_transaction = ProjectTransaction::default();
 
         for buffer in &buffers {
-            let adapters_and_servers = lsp_store.update(&mut cx, |lsp_store, cx| {
+            let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
                 buffer.update(cx, |buffer, cx| {
                     lsp_store
                         .as_local()
@@ -1123,7 +1121,7 @@ impl LocalLspStore {
                 &buffer,
                 push_to_history,
                 &mut project_transaction,
-                &mut cx,
+                cx,
             )
             .await?;
         }
@@ -1135,11 +1133,11 @@ impl LocalLspStore {
         mut buffers: Vec<FormattableBuffer>,
         push_to_history: bool,
         trigger: FormatTrigger,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> anyhow::Result<ProjectTransaction> {
         // Do not allow multiple concurrent formatting requests for the
         // same buffer.
-        lsp_store.update(&mut cx, |this, cx| {
+        lsp_store.update(cx, |this, cx| {
             let this = this.as_local_mut().unwrap();
             buffers.retain(|buffer| {
                 this.buffers_being_formatted
@@ -1165,7 +1163,7 @@ impl LocalLspStore {
 
         let mut project_transaction = ProjectTransaction::default();
         for buffer in &buffers {
-            let adapters_and_servers = lsp_store.update(&mut cx, |lsp_store, cx| {
+            let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
                 buffer.handle.update(cx, |buffer, cx| {
                     lsp_store
                         .as_local()
@@ -1176,7 +1174,7 @@ impl LocalLspStore {
                 })
             })?;
 
-            let settings = buffer.handle.update(&mut cx, |buffer, cx| {
+            let settings = buffer.handle.update(cx, |buffer, cx| {
                 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
                     .into_owned()
             })?;
@@ -1189,13 +1187,13 @@ impl LocalLspStore {
                 Some(
                     buffer
                         .handle
-                        .update(&mut cx, |b, cx| b.remove_trailing_whitespace(cx))?
+                        .update(cx, |b, cx| b.remove_trailing_whitespace(cx))?
                         .await,
                 )
             } else {
                 None
             };
-            let whitespace_transaction_id = buffer.handle.update(&mut cx, |buffer, cx| {
+            let whitespace_transaction_id = buffer.handle.update(cx, |buffer, cx| {
                 buffer.finalize_last_transaction();
                 buffer.start_transaction();
                 if let Some(diff) = trailing_whitespace_diff {
@@ -1222,12 +1220,12 @@ impl LocalLspStore {
                     &buffer.handle,
                     push_to_history,
                     &mut project_transaction,
-                    &mut cx,
+                    cx,
                 )
                 .await?;
             }
 
-            let prettier_settings = buffer.handle.read_with(&cx, |buffer, cx| {
+            let prettier_settings = buffer.handle.read_with(cx, |buffer, cx| {
                 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
                     .prettier
                     .clone()
@@ -1258,7 +1256,7 @@ impl LocalLspStore {
                 push_to_history,
                 initial_transaction_id,
                 &mut project_transaction,
-                &mut cx,
+                cx,
             )
             .await?;
         }
@@ -2539,13 +2537,13 @@ impl LocalLspStore {
         params: lsp::ApplyWorkspaceEditParams,
         server_id: LanguageServerId,
         adapter: Arc<CachedLspAdapter>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<lsp::ApplyWorkspaceEditResponse> {
         let this = this
             .upgrade()
             .ok_or_else(|| anyhow!("project project closed"))?;
         let language_server = this
-            .update(&mut cx, |this, _| this.language_server_for_id(server_id))?
+            .update(cx, |this, _| this.language_server_for_id(server_id))?
             .ok_or_else(|| anyhow!("language server not found"))?;
         let transaction = Self::deserialize_workspace_edit(
             this.clone(),
@@ -2553,11 +2551,11 @@ impl LocalLspStore {
             true,
             adapter.clone(),
             language_server.clone(),
-            &mut cx,
+            cx,
         )
         .await
         .log_err();
-        this.update(&mut cx, |this, _| {
+        this.update(cx, |this, _| {
             if let Some(transaction) = transaction {
                 this.as_local_mut()
                     .unwrap()
@@ -3123,11 +3121,11 @@ impl LspStore {
         cx: &mut Context<'_, LspStore>,
     ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
         let message = request.to_proto(upstream_project_id, buffer.read(cx));
-        cx.spawn(move |this, cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = client.request(message).await?;
             let this = this.upgrade().context("project dropped")?;
             request
-                .response_from_proto(response, this, buffer, cx)
+                .response_from_proto(response, this, buffer, cx.clone())
                 .await
         })
     }
@@ -3336,10 +3334,11 @@ impl LspStore {
         if self.as_local().is_none() {
             return;
         }
-        cx.spawn(async move |this, mut cx| {
+        cx.spawn(async move |this, cx| {
             let weak_ref = this.clone();
+
             let servers = this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     let local = this.as_local()?;
 
                     let mut servers = Vec::new();
@@ -3387,7 +3386,7 @@ impl LspStore {
                 return;
             };
 
-            let Ok(Some((fs, toolchain_store))) = this.read_with(&cx, |this, cx| {
+            let Ok(Some((fs, toolchain_store))) = this.read_with(cx, |this, cx| {
                 let local = this.as_local()?;
                 let toolchain_store = this.toolchain_store(cx);
                 return Some((local.fs.clone(), toolchain_store));
@@ -3402,7 +3401,7 @@ impl LspStore {
                         fs.as_ref(),
                         &delegate,
                         toolchain_store.clone(),
-                        &mut cx,
+                        cx,
                     )
                     .await
                     .context("generate new workspace configuration for JSON language server while trying to refresh JSON Schemas")
@@ -3487,7 +3486,7 @@ impl LspStore {
     ) -> Task<()> {
         let mut subscription = languages.subscribe();
         let mut prev_reload_count = languages.reload_count();
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             while let Some(()) = subscription.next().await {
                 if let Some(this) = this.upgrade() {
                     // If the language registry has been reloaded, then remove and
@@ -3495,7 +3494,7 @@ impl LspStore {
                     let reload_count = languages.reload_count();
                     if reload_count > prev_reload_count {
                         prev_reload_count = reload_count;
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             this.buffer_store.clone().update(cx, |buffer_store, cx| {
                                 for buffer in buffer_store.buffers() {
                                     if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
@@ -3526,7 +3525,7 @@ impl LspStore {
                         .ok();
                     }
 
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         let mut plain_text_buffers = Vec::new();
                         let mut buffers_with_unknown_injections = Vec::new();
                         for handle in this.buffer_store.read(cx).buffers() {
@@ -3761,7 +3760,7 @@ impl LspStore {
         if !request.check_capabilities(language_server.adapter_server_capabilities()) {
             return Task::ready(Ok(Default::default()));
         }
-        return cx.spawn(move |this, cx| async move {
+        return cx.spawn(async move |this, cx| {
             let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
 
             let id = lsp_request.id();
@@ -3997,7 +3996,7 @@ impl LspStore {
                 action: Some(Self::serialize_code_action(&action)),
             };
             let buffer_store = self.buffer_store();
-            cx.spawn(move |_, mut cx| async move {
+            cx.spawn(async move |_, cx| {
                 let response = upstream_client
                     .request(request)
                     .await?
@@ -4005,7 +4004,7 @@ impl LspStore {
                     .ok_or_else(|| anyhow!("missing transaction"))?;
 
                 buffer_store
-                    .update(&mut cx, |buffer_store, cx| {
+                    .update(cx, |buffer_store, cx| {
                         buffer_store.deserialize_project_transaction(response, push_to_history, cx)
                     })?
                     .await
@@ -4017,7 +4016,7 @@ impl LspStore {
             }) else {
                 return Task::ready(Ok(ProjectTransaction::default()));
             };
-            cx.spawn(move |this, mut cx| async move {
+            cx.spawn(async move |this,  cx| {
                 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
                     .await
                     .context("resolving a code action")?;
@@ -4029,7 +4028,7 @@ impl LspStore {
                             push_to_history,
                             lsp_adapter.clone(),
                             lang_server.clone(),
-                            &mut cx,
+                            cx,
                         )
                         .await;
                     }
@@ -4043,7 +4042,7 @@ impl LspStore {
                         .map(|options| options.commands.as_slice())
                         .unwrap_or_default();
                     if available_commands.contains(&command.command) {
-                        this.update(&mut cx, |this, _| {
+                        this.update(cx, |this, _| {
                             this.as_local_mut()
                                 .unwrap()
                                 .last_workspace_edits_by_language_server
@@ -4060,7 +4059,7 @@ impl LspStore {
 
                         result?;
 
-                        return this.update(&mut cx, |this, _| {
+                        return this.update(cx, |this, _| {
                             this.as_local_mut()
                                 .unwrap()
                                 .last_workspace_edits_by_language_server
@@ -4087,44 +4086,42 @@ impl LspStore {
         cx: &mut Context<Self>,
     ) -> Task<anyhow::Result<ProjectTransaction>> {
         if let Some(_) = self.as_local() {
-            cx.spawn(move |lsp_store, mut cx| async move {
+            cx.spawn(async move |lsp_store, cx| {
                 let buffers = buffers.into_iter().collect::<Vec<_>>();
                 let result = LocalLspStore::execute_code_action_kind_locally(
                     lsp_store.clone(),
                     buffers,
                     kind,
                     push_to_history,
-                    cx.clone(),
+                    cx,
                 )
                 .await;
-                lsp_store.update(&mut cx, |lsp_store, _| {
+                lsp_store.update(cx, |lsp_store, _| {
                     lsp_store.update_last_formatting_failure(&result);
                 })?;
                 result
             })
         } else if let Some((client, project_id)) = self.upstream_client() {
             let buffer_store = self.buffer_store();
-            cx.spawn(move |lsp_store, mut cx| async move {
+            cx.spawn(async move |lsp_store, cx| {
                 let result = client
                     .request(proto::ApplyCodeActionKind {
                         project_id,
                         kind: kind.as_str().to_owned(),
                         buffer_ids: buffers
                             .iter()
-                            .map(|buffer| {
-                                buffer.update(&mut cx, |buffer, _| buffer.remote_id().into())
-                            })
+                            .map(|buffer| buffer.update(cx, |buffer, _| buffer.remote_id().into()))
                             .collect::<Result<_>>()?,
                     })
                     .await
                     .and_then(|result| result.transaction.context("missing transaction"));
-                lsp_store.update(&mut cx, |lsp_store, _| {
+                lsp_store.update(cx, |lsp_store, _| {
                     lsp_store.update_last_formatting_failure(&result);
                 })?;
 
                 let transaction_response = result?;
                 buffer_store
-                    .update(&mut cx, |buffer_store, cx| {
+                    .update(cx, |buffer_store, cx| {
                         buffer_store.deserialize_project_transaction(
                             transaction_response,
                             push_to_history,
@@ -4152,7 +4149,7 @@ impl LspStore {
                 language_server_id: server_id.0 as u64,
                 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
             };
-            cx.spawn(move |_, _| async move {
+            cx.spawn(async move |_, _| {
                 let response = upstream_client
                     .request(request)
                     .await
@@ -4174,7 +4171,7 @@ impl LspStore {
                 return Task::ready(Ok(hint));
             }
             let buffer_snapshot = buffer_handle.read(cx).snapshot();
-            cx.spawn(move |_, mut cx| async move {
+            cx.spawn(async move |_, cx| {
                 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
                     InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
                 );
@@ -4187,7 +4184,7 @@ impl LspStore {
                     server_id,
                     ResolveState::Resolved,
                     false,
-                    &mut cx,
+                    cx,
                 )
                 .await?;
                 Ok(resolved_hint)
@@ -4266,7 +4263,7 @@ impl LspStore {
                 trigger,
                 version: serialize_version(&buffer.read(cx).version()),
             };
-            cx.spawn(move |_, _| async move {
+            cx.spawn(async move |_, _| {
                 client
                     .request(request)
                     .await?
@@ -4277,7 +4274,7 @@ impl LspStore {
         } else if let Some(local) = self.as_local_mut() {
             let buffer_id = buffer.read(cx).remote_id();
             local.buffers_being_formatted.insert(buffer_id);
-            cx.spawn(move |this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 let _cleanup = defer({
                     let this = this.clone();
                     let mut cx = cx.clone();
@@ -4292,11 +4289,11 @@ impl LspStore {
                 });
 
                 buffer
-                    .update(&mut cx, |buffer, _| {
+                    .update(cx, |buffer, _| {
                         buffer.wait_for_edits(Some(position.timestamp))
                     })?
                     .await?;
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     let position = position.to_point_utf16(buffer.read(cx));
                     this.on_type_format(buffer, position, trigger, false, cx)
                 })?
@@ -4374,7 +4371,7 @@ impl LspStore {
                 )),
             });
             let buffer = buffer_handle.clone();
-            cx.spawn(|weak_project, cx| async move {
+            cx.spawn(async move |weak_project, cx| {
                 let Some(project) = weak_project.upgrade() else {
                     return Ok(Vec::new());
                 };
@@ -4423,9 +4420,7 @@ impl LspStore {
                 },
                 cx,
             );
-            cx.spawn(
-                |_, _| async move { Ok(all_actions_task.await.into_iter().flatten().collect()) },
-            )
+            cx.spawn(async move |_, _| Ok(all_actions_task.await.into_iter().flatten().collect()))
         }
     }
 
@@ -4447,7 +4442,7 @@ impl LspStore {
                 )),
             });
             let buffer = buffer_handle.clone();
-            cx.spawn(|weak_project, cx| async move {
+            cx.spawn(async move |weak_project, cx| {
                 let Some(project) = weak_project.upgrade() else {
                     return Ok(Vec::new());
                 };
@@ -4485,7 +4480,7 @@ impl LspStore {
         } else {
             let code_lens_task =
                 self.request_multiple_lsp_locally(buffer_handle, None::<usize>, GetCodeLens, cx);
-            cx.spawn(|_, _| async move { Ok(code_lens_task.await.into_iter().flatten().collect()) })
+            cx.spawn(async move |_, _| Ok(code_lens_task.await.into_iter().flatten().collect()))
         }
     }
 
@@ -4562,9 +4557,9 @@ impl LspStore {
             } else {
                 None
             };
-            cx.spawn(move |this, mut cx| async move {
+            cx.spawn(async move |this,  cx| {
                 let mut tasks = Vec::with_capacity(server_ids.len());
-                this.update(&mut cx, |lsp_store, cx| {
+                this.update(cx, |lsp_store, cx| {
                     for server_id in server_ids {
                         let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
                         let lsp_timeout = lsp_timeout
@@ -4642,7 +4637,7 @@ impl LspStore {
         let buffer_id = buffer.read(cx).remote_id();
         let buffer_snapshot = buffer.read(cx).snapshot();
 
-        cx.spawn(move |this, cx| async move {
+        cx.spawn(async move |this, cx| {
             let mut did_resolve = false;
             if let Some((client, project_id)) = client {
                 for completion_index in completion_indices {
@@ -4680,7 +4675,7 @@ impl LspStore {
                     };
                     if let Some(server_id) = server_id {
                         let server_and_adapter = this
-                            .read_with(&cx, |lsp_store, _| {
+                            .read_with(cx, |lsp_store, _| {
                                 let server = lsp_store.language_server_for_id(server_id)?;
                                 let adapter =
                                     lsp_store.language_server_adapter_for_id(server.server_id())?;
@@ -4977,7 +4972,7 @@ impl LspStore {
         if let Some((client, project_id)) = self.upstream_client() {
             let buffer = buffer_handle.read(cx);
             let buffer_id = buffer.remote_id();
-            cx.spawn(move |_, mut cx| async move {
+            cx.spawn(async move |_, cx| {
                 let request = {
                     let completion = completions.borrow()[completion_index].clone();
                     proto::ApplyCompletionAdditionalEdits {
@@ -4994,12 +4989,12 @@ impl LspStore {
                 if let Some(transaction) = client.request(request).await?.transaction {
                     let transaction = language::proto::deserialize_transaction(transaction)?;
                     buffer_handle
-                        .update(&mut cx, |buffer, _| {
+                        .update(cx, |buffer, _| {
                             buffer.wait_for_edits(transaction.edit_ids.iter().copied())
                         })?
                         .await?;
                     if push_to_history {
-                        buffer_handle.update(&mut cx, |buffer, _| {
+                        buffer_handle.update(cx, |buffer, _| {
                             buffer.push_transaction(transaction.clone(), Instant::now());
                         })?;
                     }
@@ -5022,7 +5017,7 @@ impl LspStore {
             };
             let snapshot = buffer_handle.read(&cx).snapshot();
 
-            cx.spawn(move |this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 Self::resolve_completion_local(
                     server.clone(),
                     &snapshot,
@@ -5039,7 +5034,7 @@ impl LspStore {
                     .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
                 if let Some(edits) = additional_text_edits {
                     let edits = this
-                        .update(&mut cx, |this, cx| {
+                        .update(cx, |this, cx| {
                             this.as_local_mut().unwrap().edits_from_lsp(
                                 &buffer_handle,
                                 edits,
@@ -5050,7 +5045,7 @@ impl LspStore {
                         })?
                         .await?;
 
-                    buffer_handle.update(&mut cx, |buffer, cx| {
+                    buffer_handle.update(cx, |buffer, cx| {
                         buffer.finalize_last_transaction();
                         buffer.start_transaction();
 
@@ -5106,7 +5101,7 @@ impl LspStore {
                 end: Some(serialize_anchor(&range_end)),
                 version: serialize_version(&buffer_handle.read(cx).version()),
             };
-            cx.spawn(move |project, cx| async move {
+            cx.spawn(async move |project, cx| {
                 let response = client
                     .request(request)
                     .await
@@ -5128,9 +5123,9 @@ impl LspStore {
                 lsp_request,
                 cx,
             );
-            cx.spawn(move |_, mut cx| async move {
+            cx.spawn(async move |_, cx| {
                 buffer_handle
-                    .update(&mut cx, |buffer, _| {
+                    .update(cx, |buffer, _| {
                         buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
                     })?
                     .await
@@ -5161,7 +5156,7 @@ impl LspStore {
                 )),
             });
             let buffer = buffer.clone();
-            cx.spawn(|weak_project, cx| async move {
+            cx.spawn(async move |weak_project, cx| {
                 let Some(project) = weak_project.upgrade() else {
                     return Vec::new();
                 };
@@ -5203,7 +5198,7 @@ impl LspStore {
                 GetSignatureHelp { position },
                 cx,
             );
-            cx.spawn(|_, _| async move {
+            cx.spawn(async move |_, _| {
                 all_actions_task
                     .await
                     .into_iter()
@@ -5233,7 +5228,7 @@ impl LspStore {
                 )),
             });
             let buffer = buffer.clone();
-            cx.spawn(|weak_project, cx| async move {
+            cx.spawn(async move |weak_project, cx| {
                 let Some(project) = weak_project.upgrade() else {
                     return Vec::new();
                 };
@@ -5281,7 +5276,7 @@ impl LspStore {
                 GetHover { position },
                 cx,
             );
-            cx.spawn(|_, _| async move {
+            cx.spawn(async move |_, _| {
                 all_actions_task
                     .await
                     .into_iter()
@@ -5393,7 +5388,7 @@ impl LspStore {
                 requested_servers.append(&mut servers_to_query);
             }
 
-            cx.spawn(move |this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 let responses = futures::future::join_all(requests).await;
                 let this = match this.upgrade() {
                     Some(this) => this,
@@ -5402,7 +5397,7 @@ impl LspStore {
 
                 let mut symbols = Vec::new();
                 for result in responses {
-                    let core_symbols = this.update(&mut cx, |this, cx| {
+                    let core_symbols = this.update(cx, |this, cx| {
                         result
                             .lsp_symbols
                             .into_iter()
@@ -5653,11 +5648,11 @@ impl LspStore {
     pub(crate) async fn refresh_workspace_configurations(
         this: &WeakEntity<Self>,
         fs: Arc<dyn Fs>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) {
         maybe!(async move {
             let servers = this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     let Some(local) = this.as_local() else {
                         return Vec::default();
                     };
@@ -5700,17 +5695,10 @@ impl LspStore {
                 })
                 .ok()?;
 
-            let toolchain_store = this
-                .update(&mut cx, |this, cx| this.toolchain_store(cx))
-                .ok()?;
+            let toolchain_store = this.update(cx, |this, cx| this.toolchain_store(cx)).ok()?;
             for (adapter, server, delegate) in servers {
                 let settings = adapter
-                    .workspace_configuration(
-                        fs.as_ref(),
-                        &delegate,
-                        toolchain_store.clone(),
-                        &mut cx,
-                    )
+                    .workspace_configuration(fs.as_ref(), &delegate, toolchain_store.clone(), cx)
                     .await
                     .ok()?;
 
@@ -5746,9 +5734,9 @@ impl LspStore {
 
         let mut joint_future =
             futures::stream::select(settings_changed_rx, external_refresh_requests);
-        cx.spawn(move |this, cx| async move {
+        cx.spawn(async move |this, cx| {
             while let Some(()) = joint_future.next().await {
-                Self::refresh_workspace_configurations(&this, fs.clone(), cx.clone()).await;
+                Self::refresh_workspace_configurations(&this, fs.clone(), cx).await;
             }
 
             drop(settings_observation);
@@ -6015,13 +6003,11 @@ impl LspStore {
                 project_id,
                 symbol: Some(Self::serialize_symbol(symbol)),
             });
-            cx.spawn(move |this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 let response = request.await?;
                 let buffer_id = BufferId::new(response.buffer_id)?;
-                this.update(&mut cx, |this, cx| {
-                    this.wait_for_remote_buffer(buffer_id, cx)
-                })?
-                .await
+                this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
+                    .await
             })
         } else if let Some(local) = self.as_local() {
             let Some(language_server_id) = local

crates/project/src/lsp_store/clangd_ext.rs 🔗

@@ -44,9 +44,9 @@ pub fn register_notifications(
             let adapter = adapter.clone();
             let this = lsp_store;
 
-            move |params: InactiveRegionsParams, mut cx| {
+            move |params: InactiveRegionsParams, cx| {
                 let adapter = adapter.clone();
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     let diagnostics = params
                         .regions
                         .into_iter()

crates/project/src/lsp_store/rust_analyzer_ext.rs 🔗

@@ -51,7 +51,7 @@ pub fn register_notifications(lsp_store: WeakEntity<LspStore>, language_server:
     language_server
         .on_notification::<ServerStatus, _>({
             let name = name.to_string();
-            move |params, mut cx| {
+            move |params, cx| {
                 let this = this.clone();
                 let name = name.to_string();
                 if let Some(ref message) = params.message {
@@ -74,7 +74,7 @@ pub fn register_notifications(lsp_store: WeakEntity<LspStore>, language_server:
                                     lsp_name: name.clone(),
                                 };
                                 let _ = this
-                                    .update(&mut cx, |_, cx| {
+                                    .update(cx, |_, cx| {
                                         cx.emit(LspStoreEvent::LanguageServerPrompt(request));
                                     })
                                     .ok();

crates/project/src/prettier_store.rs 🔗

@@ -86,11 +86,11 @@ impl PrettierStore {
                 }
             }
         }
-        cx.spawn(|prettier_store, mut cx| async move {
+        cx.spawn(async move |prettier_store, cx| {
             while let Some(prettier_server_id) = prettier_instances_to_clean.next().await {
                 if let Some(prettier_server_id) = prettier_server_id {
                     prettier_store
-                        .update(&mut cx, |_, cx| {
+                        .update(cx, |_, cx| {
                             cx.emit(PrettierStoreEvent::LanguageServerRemoved(
                                 prettier_server_id,
                             ));
@@ -119,7 +119,7 @@ impl PrettierStore {
             Some((worktree_id, buffer_path)) => {
                 let fs = Arc::clone(&self.fs);
                 let installed_prettiers = self.prettier_instances.keys().cloned().collect();
-                cx.spawn(|lsp_store, mut cx| async move {
+                cx.spawn(async move |lsp_store, cx| {
                     match cx
                         .background_spawn(async move {
                             Prettier::locate_prettier_installation(
@@ -134,7 +134,7 @@ impl PrettierStore {
                         Ok(ControlFlow::Break(())) => None,
                         Ok(ControlFlow::Continue(None)) => {
                             let default_instance = lsp_store
-                                .update(&mut cx, |lsp_store, cx| {
+                                .update(cx, |lsp_store, cx| {
                                     lsp_store
                                         .prettiers_per_worktree
                                         .entry(worktree_id)
@@ -151,7 +151,7 @@ impl PrettierStore {
                         }
                         Ok(ControlFlow::Continue(Some(prettier_dir))) => {
                             lsp_store
-                                .update(&mut cx, |lsp_store, _| {
+                                .update(cx, |lsp_store, _| {
                                     lsp_store
                                         .prettiers_per_worktree
                                         .entry(worktree_id)
@@ -160,7 +160,7 @@ impl PrettierStore {
                                 })
                                 .ok()?;
                             if let Some(prettier_task) = lsp_store
-                                .update(&mut cx, |lsp_store, cx| {
+                                .update(cx, |lsp_store, cx| {
                                     lsp_store.prettier_instances.get_mut(&prettier_dir).map(
                                         |existing_instance| {
                                             existing_instance.prettier_task(
@@ -180,7 +180,7 @@ impl PrettierStore {
 
                             log::info!("Found prettier in {prettier_dir:?}, starting.");
                             let new_prettier_task = lsp_store
-                                .update(&mut cx, |lsp_store, cx| {
+                                .update(cx, |lsp_store, cx| {
                                     let new_prettier_task = Self::start_prettier(
                                         node,
                                         prettier_dir.clone(),
@@ -208,7 +208,7 @@ impl PrettierStore {
             }
             None => {
                 let new_task = self.default_prettier.prettier_task(&node, None, cx);
-                cx.spawn(|_, _| async move { Some((None, new_task?.log_err().await?)) })
+                cx.spawn(async move |_, _| Some((None, new_task?.log_err().await?)))
             }
         }
     }
@@ -231,7 +231,7 @@ impl PrettierStore {
                     .get(&worktree_id)
                     .cloned()
                     .unwrap_or_default();
-                cx.spawn(|lsp_store, mut cx| async move {
+                cx.spawn(async move |lsp_store, cx| {
                     match cx
                         .background_spawn(async move {
                             Prettier::locate_prettier_ignore(
@@ -248,7 +248,7 @@ impl PrettierStore {
                         Ok(ControlFlow::Continue(Some(ignore_dir))) => {
                             log::debug!("Found prettier ignore in {ignore_dir:?}");
                             lsp_store
-                                .update(&mut cx, |store, _| {
+                                .update(cx, |store, _| {
                                     store
                                         .prettier_ignores_per_worktree
                                         .entry(worktree_id)
@@ -277,9 +277,9 @@ impl PrettierStore {
         worktree_id: Option<WorktreeId>,
         cx: &mut Context<Self>,
     ) -> PrettierTask {
-        cx.spawn(|prettier_store, mut cx| async move {
+        cx.spawn(async move |prettier_store, cx| {
             log::info!("Starting prettier at path {prettier_dir:?}");
-            let new_server_id = prettier_store.update(&mut cx, |prettier_store, _| {
+            let new_server_id = prettier_store.update(cx, |prettier_store, _| {
                 prettier_store.languages.next_language_server_id()
             })?;
 
@@ -293,7 +293,7 @@ impl PrettierStore {
                 &new_prettier,
                 worktree_id,
                 new_server_id,
-                &mut cx,
+                cx,
             );
             Ok(new_prettier)
         })
@@ -305,8 +305,8 @@ impl PrettierStore {
         worktree_id: Option<WorktreeId>,
         cx: &mut Context<PrettierStore>,
     ) -> Task<anyhow::Result<PrettierTask>> {
-        cx.spawn(|prettier_store, mut cx| async move {
-            let installation_task = prettier_store.update(&mut cx, |prettier_store, _| {
+        cx.spawn(async move |prettier_store, cx| {
+            let installation_task = prettier_store.update(cx, |prettier_store, _| {
                 match &prettier_store.default_prettier.prettier {
                     PrettierInstallation::NotInstalled {
                         installation_task, ..
@@ -323,7 +323,7 @@ impl PrettierStore {
                 ControlFlow::Continue(Some(installation_task)) => {
                     log::info!("Waiting for default prettier to install");
                     if let Err(e) = installation_task.await {
-                        prettier_store.update(&mut cx, |project, _| {
+                        prettier_store.update(cx, |project, _| {
                             if let PrettierInstallation::NotInstalled {
                                 installation_task,
                                 attempts,
@@ -339,7 +339,7 @@ impl PrettierStore {
                         );
                     }
                     let new_default_prettier =
-                        prettier_store.update(&mut cx, |prettier_store, cx| {
+                        prettier_store.update(cx, |prettier_store, cx| {
                             let new_default_prettier = Self::start_prettier(
                                 node,
                                 default_prettier_dir().clone(),
@@ -359,7 +359,7 @@ impl PrettierStore {
                     Some(instance) => Ok(instance),
                     None => {
                         let new_default_prettier =
-                            prettier_store.update(&mut cx, |prettier_store, cx| {
+                            prettier_store.update(cx, |prettier_store, cx| {
                                 let new_default_prettier = Self::start_prettier(
                                     node,
                                     default_prettier_dir().clone(),
@@ -578,7 +578,7 @@ impl PrettierStore {
         let plugins_to_install = new_plugins.clone();
         let fs = Arc::clone(&self.fs);
         let new_installation_task = cx
-            .spawn(|project, mut cx| async move {
+            .spawn(async move  |project, cx| {
                 match locate_prettier_installation
                     .await
                     .context("locate prettier installation")
@@ -593,7 +593,7 @@ impl PrettierStore {
                         if let Some(previous_installation_task) = previous_installation_task {
                             if let Err(e) = previous_installation_task.await {
                                 log::error!("Failed to install default prettier: {e:#}");
-                                project.update(&mut cx, |project, _| {
+                                project.update(cx, |project, _| {
                                     if let PrettierInstallation::NotInstalled { attempts, not_installed_plugins, .. } = &mut project.default_prettier.prettier {
                                         *attempts += 1;
                                         new_plugins.extend(not_installed_plugins.iter().cloned());
@@ -604,7 +604,7 @@ impl PrettierStore {
                             }
                         };
                         if installation_attempt > prettier::FAIL_THRESHOLD {
-                            project.update(&mut cx, |project, _| {
+                            project.update(cx, |project, _| {
                                 if let PrettierInstallation::NotInstalled { installation_task, .. } = &mut project.default_prettier.prettier {
                                     *installation_task = None;
                                 };
@@ -614,7 +614,7 @@ impl PrettierStore {
                             );
                             return Ok(());
                         }
-                        project.update(&mut cx, |project, _| {
+                        project.update(cx, |project, _| {
                             new_plugins.retain(|plugin| {
                                 !project.default_prettier.installed_plugins.contains(plugin)
                             });
@@ -638,7 +638,7 @@ impl PrettierStore {
                                 .context("prettier & plugins install")
                                 .map_err(Arc::new)?;
                             log::info!("Initialized prettier with plugins: {installed_plugins:?}");
-                            project.update(&mut cx, |project, _| {
+                            project.update(cx, |project, _| {
                                 project.default_prettier.prettier =
                                     PrettierInstallation::Installed(PrettierInstance {
                                         attempt: 0,
@@ -865,9 +865,9 @@ impl PrettierInstance {
                 None => {
                     self.attempt += 1;
                     let node = node.clone();
-                    cx.spawn(|prettier_store, mut cx| async move {
+                    cx.spawn(async move |prettier_store, cx| {
                         prettier_store
-                            .update(&mut cx, |_, cx| {
+                            .update(cx, |_, cx| {
                                 PrettierStore::start_default_prettier(node, worktree_id, cx)
                             })?
                             .await

crates/project/src/project.rs 🔗

@@ -810,7 +810,7 @@ impl Project {
     ) -> Entity<Self> {
         cx.new(|cx: &mut Context<Self>| {
             let (tx, rx) = mpsc::unbounded();
-            cx.spawn(move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
+            cx.spawn(async move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx).await)
                 .detach();
             let snippets = SnippetProvider::new(fs.clone(), BTreeSet::from_iter([]), cx);
             let worktree_store = cx.new(|_| WorktreeStore::local(false, fs.clone()));
@@ -963,7 +963,7 @@ impl Project {
     ) -> Entity<Self> {
         cx.new(|cx: &mut Context<Self>| {
             let (tx, rx) = mpsc::unbounded();
-            cx.spawn(move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
+            cx.spawn(async move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx).await)
                 .detach();
             let global_snippets_dir = paths::config_dir().join("snippets");
             let snippets =
@@ -1285,7 +1285,7 @@ impl Project {
             }
 
             let (tx, rx) = mpsc::unbounded();
-            cx.spawn(move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
+            cx.spawn(async move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx).await)
                 .detach();
 
             cx.subscribe(&worktree_store, Self::on_worktree_store_event)
@@ -1856,9 +1856,9 @@ impl Project {
         let is_root_entry = self.entry_is_worktree_root(entry_id, cx);
 
         let lsp_store = self.lsp_store().downgrade();
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             let (old_abs_path, new_abs_path) = {
-                let root_path = worktree.update(&mut cx, |this, _| this.abs_path())?;
+                let root_path = worktree.update(cx, |this, _| this.abs_path())?;
                 let new_abs_path = if is_root_entry {
                     root_path.parent().unwrap().join(&new_path)
                 } else {
@@ -1877,13 +1877,13 @@ impl Project {
             .await;
 
             let entry = worktree
-                .update(&mut cx, |worktree, cx| {
+                .update(cx, |worktree, cx| {
                     worktree.rename_entry(entry_id, new_path.clone(), cx)
                 })?
                 .await?;
 
             lsp_store
-                .update(&mut cx, |this, _| {
+                .update(cx, |this, _| {
                     this.did_rename_entry(worktree_id, &old_abs_path, &new_abs_path, is_dir);
                 })
                 .ok();
@@ -1934,9 +1934,9 @@ impl Project {
         let task = worktree.update(cx, |worktree, cx| {
             worktree.expand_all_for_entry(entry_id, cx)
         });
-        Some(cx.spawn(|this, mut cx| async move {
+        Some(cx.spawn(async move |this, cx| {
             task.ok_or_else(|| anyhow!("no task"))?.await?;
-            this.update(&mut cx, |_, cx| {
+            this.update(cx, |_, cx| {
                 cx.emit(Event::ExpandedAllForEntry(worktree_id, entry_id));
             })?;
             Ok(())
@@ -2230,9 +2230,9 @@ impl Project {
         cx: &mut Context<Self>,
     ) -> Task<Result<(Option<ProjectEntryId>, AnyEntity)>> {
         let task = self.open_buffer(path.clone(), cx);
-        cx.spawn(move |_project, cx| async move {
+        cx.spawn(async move |_project, cx| {
             let buffer = task.await?;
-            let project_entry_id = buffer.read_with(&cx, |buffer, cx| {
+            let project_entry_id = buffer.read_with(cx, |buffer, cx| {
                 File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx))
             })?;
 
@@ -2287,9 +2287,9 @@ impl Project {
         cx: &mut Context<Self>,
     ) -> Task<Result<(Entity<Buffer>, lsp_store::OpenLspBufferHandle)>> {
         let buffer = self.open_buffer(path, cx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let buffer = buffer.await?;
-            let handle = this.update(&mut cx, |project, cx| {
+            let handle = this.update(cx, |project, cx| {
                 project.register_buffer_with_language_servers(&buffer, cx)
             })?;
             Ok((buffer, handle))
@@ -2345,10 +2345,10 @@ impl Project {
                 project_id,
                 id: id.into(),
             });
-            cx.spawn(move |project, mut cx| async move {
+            cx.spawn(async move |project, cx| {
                 let buffer_id = BufferId::new(request.await?.buffer_id)?;
                 project
-                    .update(&mut cx, |project, cx| {
+                    .update(cx, |project, cx| {
                         project.buffer_store.update(cx, |buffer_store, cx| {
                             buffer_store.wait_for_remote_buffer(buffer_id, cx)
                         })
@@ -2365,9 +2365,9 @@ impl Project {
         buffers: HashSet<Entity<Buffer>>,
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let save_tasks = buffers.into_iter().filter_map(|buffer| {
-                this.update(&mut cx, |this, cx| this.save_buffer(buffer, cx))
+                this.update(cx, |this, cx| this.save_buffer(buffer, cx))
                     .ok()
             });
             try_join_all(save_tasks).await?;
@@ -2427,15 +2427,14 @@ impl Project {
         });
 
         let weak_project = cx.entity().downgrade();
-        cx.spawn(move |_, mut cx| async move {
+        cx.spawn(async move |_, cx| {
             let image_item = open_image_task.await?;
             let project = weak_project
                 .upgrade()
                 .ok_or_else(|| anyhow!("Project dropped"))?;
 
-            let metadata =
-                ImageItem::load_image_metadata(image_item.clone(), project, &mut cx).await?;
-            image_item.update(&mut cx, |image_item, cx| {
+            let metadata = ImageItem::load_image_metadata(image_item.clone(), project, cx).await?;
+            image_item.update(cx, |image_item, cx| {
                 image_item.image_metadata = Some(metadata);
                 cx.emit(ImageItemEvent::MetadataUpdated);
             })?;
@@ -2447,7 +2446,7 @@ impl Project {
     async fn send_buffer_ordered_messages(
         this: WeakEntity<Self>,
         rx: UnboundedReceiver<BufferOrderedMessage>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<()> {
         const MAX_BATCH_SIZE: usize = 128;
 
@@ -2482,7 +2481,7 @@ impl Project {
         let mut changes = rx.ready_chunks(MAX_BATCH_SIZE);
 
         while let Some(changes) = changes.next().await {
-            let is_local = this.update(&mut cx, |this, _| this.is_local())?;
+            let is_local = this.update(cx, |this, _| this.is_local())?;
 
             for change in changes {
                 match change {
@@ -2503,7 +2502,7 @@ impl Project {
                     BufferOrderedMessage::Resync => {
                         operations_by_buffer_id.clear();
                         if this
-                            .update(&mut cx, |this, cx| this.synchronize_remote_buffers(cx))?
+                            .update(cx, |this, cx| this.synchronize_remote_buffers(cx))?
                             .await
                             .is_ok()
                         {
@@ -2520,11 +2519,11 @@ impl Project {
                             &mut operations_by_buffer_id,
                             &mut needs_resync_with_host,
                             is_local,
-                            &mut cx,
+                            cx,
                         )
                         .await?;
 
-                        this.update(&mut cx, |this, _| {
+                        this.update(cx, |this, _| {
                             if let Some(project_id) = this.remote_id() {
                                 this.client
                                     .send(proto::UpdateLanguageServer {
@@ -2544,7 +2543,7 @@ impl Project {
                 &mut operations_by_buffer_id,
                 &mut needs_resync_with_host,
                 is_local,
-                &mut cx,
+                cx,
             )
             .await?;
         }
@@ -2891,31 +2890,29 @@ impl Project {
     }
 
     fn recalculate_buffer_diffs(&mut self, cx: &mut Context<Self>) -> Task<()> {
-        cx.spawn(move |this, mut cx| async move {
-            loop {
-                let task = this
-                    .update(&mut cx, |this, cx| {
-                        let buffers = this
-                            .buffers_needing_diff
-                            .drain()
-                            .filter_map(|buffer| buffer.upgrade())
-                            .collect::<Vec<_>>();
-                        if buffers.is_empty() {
-                            None
-                        } else {
-                            Some(this.git_store.update(cx, |git_store, cx| {
-                                git_store.recalculate_buffer_diffs(buffers, cx)
-                            }))
-                        }
-                    })
-                    .ok()
-                    .flatten();
+        cx.spawn(async move |this, cx| loop {
+            let task = this
+                .update(cx, |this, cx| {
+                    let buffers = this
+                        .buffers_needing_diff
+                        .drain()
+                        .filter_map(|buffer| buffer.upgrade())
+                        .collect::<Vec<_>>();
+                    if buffers.is_empty() {
+                        None
+                    } else {
+                        Some(this.git_store.update(cx, |git_store, cx| {
+                            git_store.recalculate_buffer_diffs(buffers, cx)
+                        }))
+                    }
+                })
+                .ok()
+                .flatten();
 
-                if let Some(task) = task {
-                    task.await;
-                } else {
-                    break;
-                }
+            if let Some(task) = task {
+                task.await;
+            } else {
+                break;
             }
         })
     }
@@ -2975,7 +2972,7 @@ impl Project {
         cx: &App,
     ) -> Task<Option<ToolchainList>> {
         if let Some(toolchain_store) = self.toolchain_store.clone() {
-            cx.spawn(|cx| async move {
+            cx.spawn(async move |cx| {
                 cx.update(|cx| {
                     toolchain_store
                         .read(cx)
@@ -3225,7 +3222,7 @@ impl Project {
 
         let proto_client = ssh_client.read(cx).proto_client();
 
-        cx.spawn(|project, mut cx| async move {
+        cx.spawn(async move |project, cx| {
             let buffer = proto_client
                 .request(proto::OpenServerSettings {
                     project_id: SSH_PROJECT_ID,
@@ -3233,7 +3230,7 @@ impl Project {
                 .await?;
 
             let buffer = project
-                .update(&mut cx, |project, cx| {
+                .update(cx, |project, cx| {
                     project.buffer_store.update(cx, |buffer_store, cx| {
                         anyhow::Ok(
                             buffer_store
@@ -3468,7 +3465,7 @@ impl Project {
             self.find_search_candidate_buffers(&query, MAX_SEARCH_RESULT_FILES + 1, cx)
         };
 
-        cx.spawn(|_, cx| async move {
+        cx.spawn(async move |_, cx| {
             let mut range_count = 0;
             let mut buffer_count = 0;
             let mut limit_reached = false;
@@ -3485,7 +3482,7 @@ impl Project {
                 for buffer in matching_buffer_chunk {
                     let buffer = buffer.clone();
                     let query = query.clone();
-                    let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot())?;
+                    let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
                     chunk_results.push(cx.background_spawn(async move {
                         let ranges = query
                             .search(&snapshot, None)
@@ -3610,12 +3607,12 @@ impl Project {
         });
         let guard = self.retain_remotely_created_models(cx);
 
-        cx.spawn(move |project, mut cx| async move {
+        cx.spawn(async move |project, cx| {
             let response = request.await?;
             for buffer_id in response.buffer_ids {
                 let buffer_id = BufferId::new(buffer_id)?;
                 let buffer = project
-                    .update(&mut cx, |project, cx| {
+                    .update(cx, |project, cx| {
                         project.buffer_store.update(cx, |buffer_store, cx| {
                             buffer_store.wait_for_remote_buffer(buffer_id, cx)
                         })
@@ -3646,7 +3643,7 @@ impl Project {
         let task = self.lsp_store.update(cx, |lsp_store, cx| {
             lsp_store.request_lsp(buffer_handle, server, request, cx)
         });
-        cx.spawn(|_, _| async move {
+        cx.spawn(async move |_, _| {
             let result = task.await;
             drop(guard);
             result
@@ -3797,7 +3794,7 @@ impl Project {
             })
             .collect();
 
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(async move |_, mut cx| {
             if let Some(buffer_worktree_id) = buffer_worktree_id {
                 if let Some((worktree, _)) = worktrees_with_ids
                     .iter()
@@ -4515,8 +4512,8 @@ impl Project {
         };
 
         let client = self.client.clone();
-        cx.spawn(move |this, mut cx| async move {
-            let (buffers, incomplete_buffer_ids) = this.update(&mut cx, |this, cx| {
+        cx.spawn(async move |this, cx| {
+            let (buffers, incomplete_buffer_ids) = this.update(cx, |this, cx| {
                 this.buffer_store.read(cx).buffer_version_info(cx)
             })?;
             let response = client
@@ -4526,7 +4523,7 @@ impl Project {
                 })
                 .await?;
 
-            let send_updates_for_buffers = this.update(&mut cx, |this, cx| {
+            let send_updates_for_buffers = this.update(cx, |this, cx| {
                 response
                     .buffers
                     .into_iter()

crates/project/src/project_settings.rs 🔗

@@ -580,7 +580,7 @@ impl SettingsObserver {
         }
 
         let worktree = worktree.clone();
-        cx.spawn(move |this, cx| async move {
+        cx.spawn(async move |this, cx| {
             let settings_contents: Vec<(Arc<Path>, _, _)> =
                 futures::future::join_all(settings_contents).await;
             cx.update(|cx| {

crates/project/src/task_store.rs 🔗

@@ -312,9 +312,9 @@ impl TaskStore {
     ) -> Task<()> {
         let mut user_tasks_file_rx = watch_config_file(&cx.background_executor(), fs, file_path);
         let user_tasks_content = cx.background_executor().block(user_tasks_file_rx.next());
-        cx.spawn(move |task_store, mut cx| async move {
+        cx.spawn(async move |task_store, cx| {
             if let Some(user_tasks_content) = user_tasks_content {
-                let Ok(_) = task_store.update(&mut cx, |task_store, cx| {
+                let Ok(_) = task_store.update(cx, |task_store, cx| {
                     task_store
                         .update_user_tasks(None, Some(&user_tasks_content), task_kind, cx)
                         .log_err();
@@ -323,7 +323,7 @@ impl TaskStore {
                 };
             }
             while let Some(user_tasks_content) = user_tasks_file_rx.next().await {
-                let Ok(()) = task_store.update(&mut cx, |task_store, cx| {
+                let Ok(()) = task_store.update(cx, |task_store, cx| {
                     let result = task_store.update_user_tasks(
                         None,
                         Some(&user_tasks_content),
@@ -359,10 +359,10 @@ fn local_task_context_for_location(
         .and_then(|worktree_id| worktree_store.read(cx).worktree_for_id(worktree_id, cx))
         .and_then(|worktree| worktree.read(cx).root_dir());
 
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         let worktree_abs_path = worktree_abs_path.clone();
         let project_env = environment
-            .update(&mut cx, |environment, cx| {
+            .update(cx, |environment, cx| {
                 environment.get_environment(worktree_id, worktree_abs_path.clone(), cx)
             })
             .ok()?
@@ -402,7 +402,7 @@ fn remote_task_context_for_location(
     toolchain_store: Arc<dyn LanguageToolchainStore>,
     cx: &mut App,
 ) -> Task<Option<TaskContext>> {
-    cx.spawn(|cx| async move {
+    cx.spawn(async move |cx| {
         // We need to gather a client context, as the headless one may lack certain information (e.g. tree-sitter parsing is disabled there, so symbols are not available).
         let mut remote_context = cx
             .update(|cx| {
@@ -469,7 +469,7 @@ fn combine_task_variables(
         .read(cx)
         .language()
         .and_then(|language| language.context_provider());
-    cx.spawn(move |cx| async move {
+    cx.spawn(async move |cx| {
         let baseline = cx
             .update(|cx| {
                 baseline.build_context(

crates/project/src/terminals.rs 🔗

@@ -115,17 +115,17 @@ impl Project {
         }
         let settings = TerminalSettings::get(settings_location, cx).clone();
 
-        cx.spawn(move |project, mut cx| async move {
+        cx.spawn(async move |project, cx| {
             let python_venv_directory = if let Some(path) = path.clone() {
                 project
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         this.python_venv_directory(path, settings.detect_venv.clone(), cx)
                     })?
                     .await
             } else {
                 None
             };
-            project.update(&mut cx, |project, cx| {
+            project.update(cx, |project, cx| {
                 project.create_terminal_with_venv(kind, python_venv_directory, window, cx)
             })?
         })
@@ -406,13 +406,13 @@ impl Project {
         venv_settings: VenvSettings,
         cx: &Context<Project>,
     ) -> Task<Option<PathBuf>> {
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             if let Some((worktree, _)) = this
-                .update(&mut cx, |this, cx| this.find_worktree(&abs_path, cx))
+                .update(cx, |this, cx| this.find_worktree(&abs_path, cx))
                 .ok()?
             {
                 let toolchain = this
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         this.active_toolchain(
                             worktree.read(cx).id(),
                             LanguageName::new("Python"),
@@ -428,7 +428,7 @@ impl Project {
                 }
             }
             let venv_settings = venv_settings.as_option()?;
-            this.update(&mut cx, move |this, cx| {
+            this.update(cx, move |this, cx| {
                 if let Some(path) = this.find_venv_in_worktree(&abs_path, &venv_settings, cx) {
                     return Some(path);
                 }

crates/project/src/toolchain_store.rs 🔗

@@ -288,8 +288,8 @@ impl LocalToolchainStore {
         toolchain: Toolchain,
         cx: &mut Context<Self>,
     ) -> Task<Option<()>> {
-        cx.spawn(move |this, mut cx| async move {
-            this.update(&mut cx, |this, cx| {
+        cx.spawn(async move |this, cx| {
+            this.update(cx, |this, cx| {
                 this.active_toolchains.insert(
                     (worktree_id, toolchain.language_name.clone()),
                     toolchain.clone(),
@@ -317,9 +317,9 @@ impl LocalToolchainStore {
         };
 
         let environment = self.project_environment.clone();
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let project_env = environment
-                .update(&mut cx, |environment, cx| {
+                .update(cx, |environment, cx| {
                     environment.get_environment(Some(worktree_id), Some(root.clone()), cx)
                 })
                 .ok()?
@@ -363,7 +363,7 @@ impl RemoteToolchainStore {
     ) -> Task<Option<()>> {
         let project_id = self.project_id;
         let client = self.client.clone();
-        cx.spawn(move |_| async move {
+        cx.spawn(async move |_| {
             let path = PathBuf::from(toolchain.path.to_string());
             let _ = client
                 .request(proto::ActivateToolchain {
@@ -390,7 +390,7 @@ impl RemoteToolchainStore {
     ) -> Task<Option<ToolchainList>> {
         let project_id = self.project_id;
         let client = self.client.clone();
-        cx.spawn(move |_| async move {
+        cx.spawn(async move |_| {
             let response = client
                 .request(proto::ListToolchains {
                     project_id,
@@ -441,7 +441,7 @@ impl RemoteToolchainStore {
     ) -> Task<Option<Toolchain>> {
         let project_id = self.project_id;
         let client = self.client.clone();
-        cx.spawn(move |_| async move {
+        cx.spawn(async move |_| {
             let response = client
                 .request(proto::ActiveToolchain {
                     project_id,

crates/project/src/worktree_store.rs 🔗

@@ -237,9 +237,9 @@ impl WorktreeStore {
                 .insert(abs_path.clone(), task.shared());
         }
         let task = self.loading_worktrees.get(&abs_path).unwrap().clone();
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = task.await;
-            this.update(&mut cx, |this, _| this.loading_worktrees.remove(&abs_path))
+            this.update(cx, |this, _| this.loading_worktrees.remove(&abs_path))
                 .ok();
             match result {
                 Ok(worktree) => Ok(worktree),
@@ -266,7 +266,7 @@ impl WorktreeStore {
         if abs_path.is_empty() || abs_path == "/" {
             abs_path = "~/".to_string();
         }
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let this = this.upgrade().context("Dropped worktree store")?;
 
             let path = Path::new(abs_path.as_str());
@@ -278,7 +278,7 @@ impl WorktreeStore {
                 })
                 .await?;
 
-            if let Some(existing_worktree) = this.read_with(&cx, |this, cx| {
+            if let Some(existing_worktree) = this.read_with(cx, |this, cx| {
                 this.worktree_for_id(WorktreeId::from_proto(response.worktree_id), cx)
             })? {
                 return Ok(existing_worktree);
@@ -305,7 +305,7 @@ impl WorktreeStore {
                 )
             })?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.add(&worktree, cx);
             })?;
             Ok(worktree)
@@ -322,12 +322,12 @@ impl WorktreeStore {
         let next_entry_id = self.next_entry_id.clone();
         let path: SanitizedPath = abs_path.into();
 
-        cx.spawn(move |this, mut cx| async move {
-            let worktree = Worktree::local(path.clone(), visible, fs, next_entry_id, &mut cx).await;
+        cx.spawn(async move |this, cx| {
+            let worktree = Worktree::local(path.clone(), visible, fs, next_entry_id, cx).await;
 
             let worktree = worktree?;
 
-            this.update(&mut cx, |this, cx| this.add(&worktree, cx))?;
+            this.update(cx, |this, cx| this.add(&worktree, cx))?;
 
             if visible {
                 cx.update(|cx| {
@@ -554,12 +554,12 @@ impl WorktreeStore {
             downstream_client.send(update).log_err();
             None
         };
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             if let Some(update_project) = update_project {
                 update_project.await?;
             }
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let worktrees = this.worktrees().collect::<Vec<_>>();
 
                 for worktree in worktrees {

crates/project/src/yarn.rs 🔗

@@ -91,9 +91,9 @@ impl YarnPathStore {
         };
         if let Some(zip_file) = zip_path(&path) {
             let zip_file: Arc<Path> = Arc::from(zip_file);
-            cx.spawn(|this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 let dir = this
-                    .update(&mut cx, |this, _| {
+                    .update(cx, |this, _| {
                         this.temp_dirs
                             .get(&zip_file)
                             .map(|temp| temp.path().to_owned())
@@ -102,10 +102,10 @@ impl YarnPathStore {
                 let zip_root = if let Some(dir) = dir {
                     dir
                 } else {
-                    let fs = this.update(&mut cx, |this, _| this.fs.clone()).ok()?;
+                    let fs = this.update(cx, |this, _| this.fs.clone()).ok()?;
                     let tempdir = dump_zip(zip_file.clone(), fs).await.log_err()?;
                     let new_path = tempdir.path().to_owned();
-                    this.update(&mut cx, |this, _| {
+                    this.update(cx, |this, _| {
                         this.temp_dirs.insert(zip_file.clone(), tempdir);
                     })
                     .ok()?;

crates/project_panel/src/project_panel.rs 🔗

@@ -1162,23 +1162,23 @@ impl ProjectPanel {
         edit_state.processing_filename = Some(filename);
         cx.notify();
 
-        Some(cx.spawn_in(window, |project_panel, mut cx| async move {
+        Some(cx.spawn_in(window, async move |project_panel, cx| {
             let new_entry = edit_task.await;
-            project_panel.update(&mut cx, |project_panel, cx| {
+            project_panel.update(cx, |project_panel, cx| {
                 project_panel.edit_state = None;
                 cx.notify();
             })?;
 
             match new_entry {
                 Err(e) => {
-                    project_panel.update(&mut cx, |project_panel, cx| {
+                    project_panel.update( cx, |project_panel, cx| {
                         project_panel.marked_entries.clear();
                         project_panel.update_visible_entries(None,  cx);
                     }).ok();
                     Err(e)?;
                 }
                 Ok(CreatedEntry::Included(new_entry)) => {
-                    project_panel.update(&mut cx, |project_panel, cx| {
+                    project_panel.update( cx, |project_panel, cx| {
                         if let Some(selection) = &mut project_panel.selection {
                             if selection.entry_id == edited_entry_id {
                                 selection.worktree_id = worktree_id;
@@ -1196,7 +1196,7 @@ impl ProjectPanel {
                 }
                 Ok(CreatedEntry::Excluded { abs_path }) => {
                     if let Some(open_task) = project_panel
-                        .update_in(&mut cx, |project_panel, window, cx| {
+                        .update_in( cx, |project_panel, window, cx| {
                             project_panel.marked_entries.clear();
                             project_panel.update_visible_entries(None,  cx);
 
@@ -1494,7 +1494,7 @@ impl ProjectPanel {
                 None
             };
             let next_selection = self.find_next_selection_after_deletion(items_to_delete, cx);
-            cx.spawn_in(window, |panel, mut cx| async move {
+            cx.spawn_in(window, async move |panel, cx| {
                 if let Some(answer) = answer {
                     if answer.await != Ok(0) {
                         return anyhow::Ok(());
@@ -1502,7 +1502,7 @@ impl ProjectPanel {
                 }
                 for (entry_id, _) in file_paths {
                     panel
-                        .update(&mut cx, |panel, cx| {
+                        .update(cx, |panel, cx| {
                             panel
                                 .project
                                 .update(cx, |project, cx| project.delete_entry(entry_id, trash, cx))
@@ -1510,7 +1510,7 @@ impl ProjectPanel {
                         })??
                         .await?;
                 }
-                panel.update_in(&mut cx, |panel, window, cx| {
+                panel.update_in(cx, |panel, window, cx| {
                     if let Some(next_selection) = next_selection {
                         panel.selection = Some(next_selection);
                         panel.autoscroll(cx);
@@ -2105,7 +2105,7 @@ impl ProjectPanel {
 
             let item_count = paste_entry_tasks.len();
 
-            cx.spawn_in(window, |project_panel, mut cx| async move {
+            cx.spawn_in(window, async move |project_panel, cx| {
                 let mut last_succeed = None;
                 let mut need_delete_ids = Vec::new();
                 for ((entry_id, need_delete), task) in paste_entry_tasks.into_iter() {
@@ -2128,7 +2128,7 @@ impl ProjectPanel {
                 // remove entry for cut in difference worktree
                 for entry_id in need_delete_ids {
                     project_panel
-                        .update(&mut cx, |project_panel, cx| {
+                        .update(cx, |project_panel, cx| {
                             project_panel
                                 .project
                                 .update(cx, |project, cx| project.delete_entry(entry_id, true, cx))
@@ -2139,7 +2139,7 @@ impl ProjectPanel {
                 // update selection
                 if let Some(entry) = last_succeed {
                     project_panel
-                        .update_in(&mut cx, |project_panel, window, cx| {
+                        .update_in(cx, |project_panel, window, cx| {
                             project_panel.selection = Some(SelectedEntry {
                                 worktree_id,
                                 entry_id: entry.id,
@@ -2884,7 +2884,7 @@ impl ProjectPanel {
             }
         }
 
-        cx.spawn_in(window, |this, mut cx| {
+        cx.spawn_in(window, async move |this, cx| {
             async move {
                 for (filename, original_path) in &paths_to_replace {
                     let answer = cx.update(|window, cx| {
@@ -2909,18 +2909,18 @@ impl ProjectPanel {
                     return Ok(());
                 }
 
-                let task = worktree.update(&mut cx, |worktree, cx| {
+                let task = worktree.update( cx, |worktree, cx| {
                     worktree.copy_external_entries(target_directory, paths, true, cx)
                 })?;
 
                 let opened_entries = task.await?;
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     if open_file_after_drop && !opened_entries.is_empty() {
                         this.open_entry(opened_entries[0], true, false, cx);
                     }
                 })
             }
-            .log_err()
+            .log_err().await
         })
         .detach();
     }
@@ -2962,7 +2962,7 @@ impl ProjectPanel {
 
                 let item_count = copy_tasks.len();
 
-                cx.spawn_in(window, |project_panel, mut cx| async move {
+                cx.spawn_in(window, async move |project_panel, cx| {
                     let mut last_succeed = None;
                     for task in copy_tasks.into_iter() {
                         if let Some(Some(entry)) = task.await.log_err() {
@@ -2972,7 +2972,7 @@ impl ProjectPanel {
                     // update selection
                     if let Some(entry_id) = last_succeed {
                         project_panel
-                            .update_in(&mut cx, |project_panel, window, cx| {
+                            .update_in(cx, |project_panel, window, cx| {
                                 project_panel.selection = Some(SelectedEntry {
                                     worktree_id,
                                     entry_id,
@@ -3679,11 +3679,11 @@ impl ProjectPanel {
 
                         let bounds = event.bounds;
                         this.hover_expand_task =
-                            Some(cx.spawn_in(window, |this, mut cx| async move {
+                            Some(cx.spawn_in(window, async move |this, cx| {
                                 cx.background_executor()
                                     .timer(Duration::from_millis(500))
                                     .await;
-                                this.update_in(&mut cx, |this, window, cx| {
+                                this.update_in(cx, |this, window, cx| {
                                     this.hover_expand_task.take();
                                     if this.last_selection_drag_over_entry == Some(entry_id)
                                         && bounds.contains(&window.mouse_position())
@@ -4221,12 +4221,12 @@ impl ProjectPanel {
         if !Self::should_autohide_scrollbar(cx) {
             return;
         }
-        self.hide_scrollbar_task = Some(cx.spawn_in(window, |panel, mut cx| async move {
+        self.hide_scrollbar_task = Some(cx.spawn_in(window, async move |panel, cx| {
             cx.background_executor()
                 .timer(SCROLLBAR_SHOW_INTERVAL)
                 .await;
             panel
-                .update(&mut cx, |panel, cx| {
+                .update(cx, |panel, cx| {
                     panel.show_scrollbar = false;
                     cx.notify();
                 })
@@ -4387,30 +4387,27 @@ impl Render for ProjectPanel {
                     return;
                 };
                 let adjustment = point(px(0.), px(vertical_scroll_offset));
-                this.hover_scroll_task =
-                    Some(cx.spawn_in(window, move |this, mut cx| async move {
-                        loop {
-                            let should_stop_scrolling = this
-                                .update(&mut cx, |this, cx| {
-                                    this.hover_scroll_task.as_ref()?;
-                                    let handle = this.scroll_handle.0.borrow_mut();
-                                    let offset = handle.base_handle.offset();
-
-                                    handle.base_handle.set_offset(offset + adjustment);
-                                    cx.notify();
-                                    Some(())
-                                })
-                                .ok()
-                                .flatten()
-                                .is_some();
-                            if should_stop_scrolling {
-                                return;
-                            }
-                            cx.background_executor()
-                                .timer(Duration::from_millis(16))
-                                .await;
-                        }
-                    }));
+                this.hover_scroll_task = Some(cx.spawn_in(window, async move |this, cx| loop {
+                    let should_stop_scrolling = this
+                        .update(cx, |this, cx| {
+                            this.hover_scroll_task.as_ref()?;
+                            let handle = this.scroll_handle.0.borrow_mut();
+                            let offset = handle.base_handle.offset();
+
+                            handle.base_handle.set_offset(offset + adjustment);
+                            cx.notify();
+                            Some(())
+                        })
+                        .ok()
+                        .flatten()
+                        .is_some();
+                    if should_stop_scrolling {
+                        return;
+                    }
+                    cx.background_executor()
+                        .timer(Duration::from_millis(16))
+                        .await;
+                }));
             }
             h_flex()
                 .id("project-panel")
@@ -9820,7 +9817,7 @@ mod tests {
             cx: &mut App,
         ) -> Option<Task<gpui::Result<Entity<Self>>>> {
             let path = path.clone();
-            Some(cx.spawn(|mut cx| async move { cx.new(|_| Self { path }) }))
+            Some(cx.spawn(async move |cx| cx.new(|_| Self { path })))
         }
 
         fn entry_id(&self, _: &App) -> Option<ProjectEntryId> {

crates/project_symbols/src/project_symbols.rs 🔗

@@ -118,9 +118,9 @@ impl PickerDelegate for ProjectSymbolsDelegate {
             });
             let symbol = symbol.clone();
             let workspace = self.workspace.clone();
-            cx.spawn_in(window, |_, mut cx| async move {
+            cx.spawn_in(window, async move |_, cx| {
                 let buffer = buffer.await?;
-                workspace.update_in(&mut cx, |workspace, window, cx| {
+                workspace.update_in(cx, |workspace, window, cx| {
                     let position = buffer
                         .read(cx)
                         .clip_point_utf16(symbol.range.start, Bias::Left);
@@ -176,10 +176,10 @@ impl PickerDelegate for ProjectSymbolsDelegate {
         let symbols = self
             .project
             .update(cx, |project, cx| project.symbols(&query, cx));
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let symbols = symbols.await.log_err();
             if let Some(symbols) = symbols {
-                this.update_in(&mut cx, |this, window, cx| {
+                this.update_in(cx, |this, window, cx| {
                     let delegate = &mut this.delegate;
                     let project = delegate.project.read(cx);
                     let (visible_match_candidates, external_match_candidates) = symbols

crates/prompt_library/src/prompt_library.rs 🔗

@@ -78,7 +78,7 @@ pub fn open_prompt_library(
     cx: &mut App,
 ) -> Task<Result<WindowHandle<PromptLibrary>>> {
     let store = PromptStore::global(cx);
-    cx.spawn(|cx| async move {
+    cx.spawn(async move |cx| {
         // We query windows in spawn so that all windows have been returned to GPUI
         let existing_window = cx
             .update(|cx| {
@@ -213,7 +213,7 @@ impl PickerDelegate for PromptPickerDelegate {
     ) -> Task<()> {
         let search = self.store.search(query);
         let prev_prompt_id = self.matches.get(self.selected_index).map(|mat| mat.id);
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let (matches, selected_index) = cx
                 .background_spawn(async move {
                     let matches = search.await;
@@ -227,7 +227,7 @@ impl PickerDelegate for PromptPickerDelegate {
                 })
                 .await;
 
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.delegate.matches = matches;
                 this.delegate.set_selected_index(selected_index, window, cx);
                 cx.notify();
@@ -409,9 +409,9 @@ impl PromptLibrary {
         let save = self.store.save(prompt_id, None, false, "".into());
         self.picker
             .update(cx, |picker, cx| picker.refresh(window, cx));
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             save.await?;
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.load_prompt(prompt_id, true, window, cx)
             })
         })
@@ -449,10 +449,10 @@ impl PromptLibrary {
 
         prompt_editor.next_title_and_body_to_save = Some((title, body));
         if prompt_editor.pending_save.is_none() {
-            prompt_editor.pending_save = Some(cx.spawn_in(window, |this, mut cx| {
+            prompt_editor.pending_save = Some(cx.spawn_in(window, async move |this, cx| {
                 async move {
                     loop {
-                        let title_and_body = this.update(&mut cx, |this, _| {
+                        let title_and_body = this.update(cx, |this, _| {
                             this.prompt_editors
                                 .get_mut(&prompt_id)?
                                 .next_title_and_body_to_save
@@ -469,7 +469,7 @@ impl PromptLibrary {
                                 .save(prompt_id, title, prompt_metadata.default, body)
                                 .await
                                 .log_err();
-                            this.update_in(&mut cx, |this, window, cx| {
+                            this.update_in(cx, |this, window, cx| {
                                 this.picker
                                     .update(cx, |picker, cx| picker.refresh(window, cx));
                                 cx.notify();
@@ -481,13 +481,14 @@ impl PromptLibrary {
                         }
                     }
 
-                    this.update(&mut cx, |this, _cx| {
+                    this.update(cx, |this, _cx| {
                         if let Some(prompt_editor) = this.prompt_editors.get_mut(&prompt_id) {
                             prompt_editor.pending_save = None;
                         }
                     })
                 }
                 .log_err()
+                .await
             }));
         }
     }
@@ -548,10 +549,10 @@ impl PromptLibrary {
             let language_registry = self.language_registry.clone();
             let prompt = self.store.load(prompt_id);
             let make_completion_provider = self.make_completion_provider.clone();
-            self.pending_load = cx.spawn_in(window, |this, mut cx| async move {
+            self.pending_load = cx.spawn_in(window, async move |this, cx| {
                 let prompt = prompt.await;
                 let markdown = language_registry.language_for_name("Markdown").await;
-                this.update_in(&mut cx, |this, window, cx| match prompt {
+                this.update_in(cx, |this, window, cx| match prompt {
                     Ok(prompt) => {
                         let title_editor = cx.new(|cx| {
                             let mut editor = Editor::auto_width(window, cx);
@@ -684,9 +685,9 @@ impl PromptLibrary {
                 cx,
             );
 
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 if confirmation.await.ok() == Some(0) {
-                    this.update_in(&mut cx, |this, window, cx| {
+                    this.update_in(cx, |this, window, cx| {
                         if this.active_prompt_id == Some(prompt_id) {
                             this.set_active_prompt(None, window, cx);
                         }
@@ -740,9 +741,9 @@ impl PromptLibrary {
                 .save(new_id, Some(title.into()), false, body.into());
             self.picker
                 .update(cx, |picker, cx| picker.refresh(window, cx));
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 save.await?;
-                this.update_in(&mut cx, |prompt_library, window, cx| {
+                this.update_in(cx, |prompt_library, window, cx| {
                     prompt_library.load_prompt(new_id, true, window, cx)
                 })
             })
@@ -886,7 +887,7 @@ impl PromptLibrary {
             let editor = &prompt.body_editor.read(cx);
             let buffer = &editor.buffer().read(cx).as_singleton().unwrap().read(cx);
             let body = buffer.as_rope().clone();
-            prompt.pending_token_count = cx.spawn_in(window, |this, mut cx| {
+            prompt.pending_token_count = cx.spawn_in(window, async move |this, cx| {
                 async move {
                     const DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
 
@@ -909,13 +910,14 @@ impl PromptLibrary {
                         })?
                         .await?;
 
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         let prompt_editor = this.prompt_editors.get_mut(&prompt_id).unwrap();
                         prompt_editor.token_count = Some(token_count);
                         cx.notify();
                     })
                 }
                 .log_err()
+                .await
             });
         }
     }

crates/recent_projects/src/disconnected_overlay.rs 🔗

@@ -118,7 +118,7 @@ impl DisconnectedOverlay {
 
         let paths = ssh_project.paths.iter().map(PathBuf::from).collect();
 
-        cx.spawn_in(window, move |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             open_ssh_project(
                 connection_options,
                 paths,
@@ -127,7 +127,7 @@ impl DisconnectedOverlay {
                     replace_window: Some(window_handle),
                     ..Default::default()
                 },
-                &mut cx,
+                cx,
             )
             .await?;
             Ok(())

crates/recent_projects/src/recent_projects.rs 🔗

@@ -62,13 +62,13 @@ impl RecentProjects {
         let _subscription = cx.subscribe(&picker, |_, _, _, cx| cx.emit(DismissEvent));
         // We do not want to block the UI on a potentially lengthy call to DB, so we're gonna swap
         // out workspace locations once the future runs to completion.
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let workspaces = WORKSPACE_DB
                 .recent_workspaces_on_disk()
                 .await
                 .log_err()
                 .unwrap_or_default();
-            this.update_in(&mut cx, move |this, window, cx| {
+            this.update_in(cx, move |this, window, cx| {
                 this.picker.update(cx, move |picker, cx| {
                     picker.delegate.set_workspaces(workspaces);
                     picker.update_matches(picker.query(cx), window, cx)
@@ -281,9 +281,9 @@ impl PickerDelegate for RecentProjectsDelegate {
                             SerializedWorkspaceLocation::Local(paths, _) => {
                                 let paths = paths.paths().to_vec();
                                 if replace_current_window {
-                                    cx.spawn_in(window, move |workspace, mut cx| async move {
+                                    cx.spawn_in(window, async move |workspace, cx| {
                                         let continue_replacing = workspace
-                                            .update_in(&mut cx, |workspace, window, cx| {
+                                            .update_in(cx, |workspace, window, cx| {
                                                 workspace.prepare_to_close(
                                                     CloseIntent::ReplaceWindow,
                                                     window,
@@ -293,7 +293,7 @@ impl PickerDelegate for RecentProjectsDelegate {
                                             .await?;
                                         if continue_replacing {
                                             workspace
-                                                .update_in(&mut cx, |workspace, window, cx| {
+                                                .update_in(cx, |workspace, window, cx| {
                                                     workspace.open_workspace_for_paths(
                                                         true, paths, window, cx,
                                                     )
@@ -330,13 +330,13 @@ impl PickerDelegate for RecentProjectsDelegate {
 
                                 let paths = ssh_project.paths.iter().map(PathBuf::from).collect();
 
-                                cx.spawn_in(window, |_, mut cx| async move {
+                                cx.spawn_in(window, async move |_, cx| {
                                     open_ssh_project(
                                         connection_options,
                                         paths,
                                         app_state,
                                         open_options,
-                                        &mut cx,
+                                        cx,
                                     )
                                     .await
                                 })
@@ -541,13 +541,13 @@ impl RecentProjectsDelegate {
     ) {
         if let Some(selected_match) = self.matches.get(ix) {
             let (workspace_id, _) = self.workspaces[selected_match.candidate_id];
-            cx.spawn_in(window, move |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 let _ = WORKSPACE_DB.delete_workspace_by_id(workspace_id).await;
                 let workspaces = WORKSPACE_DB
                     .recent_workspaces_on_disk()
                     .await
                     .unwrap_or_default();
-                this.update_in(&mut cx, move |picker, window, cx| {
+                this.update_in(cx, move |picker, window, cx| {
                     picker.delegate.set_workspaces(workspaces);
                     picker
                         .delegate

crates/recent_projects/src/remote_servers.rs 🔗

@@ -141,10 +141,10 @@ impl ProjectPicker {
         let _path_task = cx
             .spawn_in(window, {
                 let workspace = workspace.clone();
-                move |this, mut cx| async move {
+                async move |this, cx| {
                     let Ok(Some(paths)) = rx.await else {
                         workspace
-                            .update_in(&mut cx, |workspace, window, cx| {
+                            .update_in(cx, |workspace, window, cx| {
                                 let weak = cx.entity().downgrade();
                                 workspace.toggle_modal(window, cx, |window, cx| {
                                     RemoteServerProjects::new(window, cx, weak)
@@ -155,7 +155,7 @@ impl ProjectPicker {
                     };
 
                     let app_state = workspace
-                        .update(&mut cx, |workspace, _| workspace.app_state().clone())
+                        .update(cx, |workspace, _| workspace.app_state().clone())
                         .ok()?;
                     let options = cx
                         .update(|_, cx| (app_state.build_window_options)(None, cx))
@@ -190,7 +190,7 @@ impl ProjectPicker {
                             })
                             .collect::<Vec<_>>();
                         window
-                            .spawn(cx, |_| async move {
+                            .spawn(cx, async move |_| {
                                 for task in tasks {
                                     task.await?;
                                 }
@@ -206,7 +206,7 @@ impl ProjectPicker {
                         })
                     })
                     .log_err();
-                    this.update(&mut cx, |_, cx| {
+                    this.update(cx, |_, cx| {
                         cx.emit(DismissEvent);
                     })
                     .ok();
@@ -404,10 +404,10 @@ impl RemoteServerProjects {
         .prompt_err("Failed to connect", window, cx, |_, _, _| None);
 
         let address_editor = editor.clone();
-        let creating = cx.spawn(move |this, mut cx| async move {
+        let creating = cx.spawn(async move |this, cx| {
             match connection.await {
                 Some(Some(client)) => this
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         telemetry::event!("SSH Server Created");
                         this.retained_connections.push(client);
                         this.add_ssh_server(connection_options, cx);
@@ -416,7 +416,7 @@ impl RemoteServerProjects {
                     })
                     .log_err(),
                 _ => this
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         address_editor.update(cx, |this, _| {
                             this.set_read_only(false);
                         });
@@ -492,11 +492,11 @@ impl RemoteServerProjects {
                 )
                 .prompt_err("Failed to connect", window, cx, |_, _, _| None);
 
-                cx.spawn_in(window, move |workspace, mut cx| async move {
+                cx.spawn_in(window, async move |workspace, cx| {
                     let session = connect.await;
 
                     workspace
-                        .update(&mut cx, |workspace, cx| {
+                        .update(cx, |workspace, cx| {
                             if let Some(prompt) = workspace.active_modal::<SshConnectionModal>(cx) {
                                 prompt.update(cx, |prompt, cx| prompt.finished(cx))
                             }
@@ -505,7 +505,7 @@ impl RemoteServerProjects {
 
                     let Some(Some(session)) = session else {
                         workspace
-                            .update_in(&mut cx, |workspace, window, cx| {
+                            .update_in(cx, |workspace, window, cx| {
                                 let weak = cx.entity().downgrade();
                                 workspace.toggle_modal(window, cx, |window, cx| {
                                     RemoteServerProjects::new(window, cx, weak)
@@ -516,7 +516,7 @@ impl RemoteServerProjects {
                     };
 
                     workspace
-                        .update_in(&mut cx, |workspace, window, cx| {
+                        .update_in(cx, |workspace, window, cx| {
                             let app_state = workspace.app_state().clone();
                             let weak = cx.entity().downgrade();
                             let project = project::Project::ssh(
@@ -758,13 +758,13 @@ impl RemoteServerProjects {
                 let project = project.clone();
                 let server = server.connection.clone();
                 cx.emit(DismissEvent);
-                cx.spawn_in(window, |_, mut cx| async move {
+                cx.spawn_in(window, async move |_, cx| {
                     let result = open_ssh_project(
                         server.into(),
                         project.paths.into_iter().map(PathBuf::from).collect(),
                         app_state,
                         OpenOptions::default(),
-                        &mut cx,
+                        cx,
                     )
                     .await;
                     if let Err(e) = result {
@@ -1111,15 +1111,15 @@ impl RemoteServerProjects {
                                     cx,
                                 );
 
-                                cx.spawn(|mut cx| async move {
+                                cx.spawn(async move |cx| {
                                     if confirmation.await.ok() == Some(0) {
                                         remote_servers
-                                            .update(&mut cx, |this, cx| {
+                                            .update(cx, |this, cx| {
                                                 this.delete_ssh_server(index, cx);
                                             })
                                             .ok();
                                         remote_servers
-                                            .update(&mut cx, |this, cx| {
+                                            .update(cx, |this, cx| {
                                                 this.mode = Mode::default_mode(cx);
                                                 cx.notify();
                                             })

crates/recent_projects/src/ssh_connections.rs 🔗

@@ -455,13 +455,13 @@ impl remote::SshClientDelegate for SshClientDelegate {
         version: Option<SemanticVersion>,
         cx: &mut AsyncApp,
     ) -> Task<anyhow::Result<PathBuf>> {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let binary_path = AutoUpdater::download_remote_server_release(
                 platform.os,
                 platform.arch,
                 release_channel,
                 version,
-                &mut cx,
+                cx,
             )
             .await
             .map_err(|e| {
@@ -486,13 +486,13 @@ impl remote::SshClientDelegate for SshClientDelegate {
         version: Option<SemanticVersion>,
         cx: &mut AsyncApp,
     ) -> Task<Result<Option<(String, String)>>> {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             AutoUpdater::get_remote_server_release_url(
                 platform.os,
                 platform.arch,
                 release_channel,
                 version,
-                &mut cx,
+                cx,
             )
             .await
         })

crates/remote/src/ssh_session.rs 🔗

@@ -615,7 +615,7 @@ impl SshRemoteClient {
         cx: &mut App,
     ) -> Task<Result<Option<Entity<Self>>>> {
         let unique_identifier = unique_identifier.to_string(cx);
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let success = Box::pin(async move {
                 let (outgoing_tx, outgoing_rx) = mpsc::unbounded::<Envelope>();
                 let (incoming_tx, incoming_rx) = mpsc::unbounded::<Envelope>();
@@ -646,7 +646,7 @@ impl SshRemoteClient {
                     outgoing_rx,
                     connection_activity_tx,
                     delegate.clone(),
-                    &mut cx,
+                    cx,
                 );
 
                 let multiplex_task = Self::monitor(this.downgrade(), io_task, &cx);
@@ -656,10 +656,9 @@ impl SshRemoteClient {
                     return Err(error);
                 }
 
-                let heartbeat_task =
-                    Self::heartbeat(this.downgrade(), connection_activity_rx, &mut cx);
+                let heartbeat_task = Self::heartbeat(this.downgrade(), connection_activity_rx, cx);
 
-                this.update(&mut cx, |this, _| {
+                this.update(cx, |this, _| {
                     *this.state.lock() = Some(State::Connected {
                         ssh_connection,
                         delegate,
@@ -784,7 +783,7 @@ impl SshRemoteClient {
 
         let unique_identifier = self.unique_identifier.clone();
         let client = self.client.clone();
-        let reconnect_task = cx.spawn(|this, mut cx| async move {
+        let reconnect_task = cx.spawn(async move |this, cx| {
             macro_rules! failed {
                 ($error:expr, $attempts:expr, $ssh_connection:expr, $delegate:expr) => {
                     return State::ReconnectFailed {
@@ -825,7 +824,7 @@ impl SshRemoteClient {
                     outgoing_rx,
                     connection_activity_tx,
                     delegate.clone(),
-                    &mut cx,
+                    cx,
                 );
                 anyhow::Ok((ssh_connection, io_task))
             }
@@ -848,13 +847,13 @@ impl SshRemoteClient {
                 ssh_connection,
                 delegate,
                 multiplex_task,
-                heartbeat_task: Self::heartbeat(this.clone(), connection_activity_rx, &mut cx),
+                heartbeat_task: Self::heartbeat(this.clone(), connection_activity_rx, cx),
             }
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let new_state = reconnect_task.await;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.try_set_state(cx, |old_state| {
                     if old_state.is_reconnecting() {
                         match &new_state {
@@ -908,9 +907,7 @@ impl SshRemoteClient {
             return Task::ready(Err(anyhow!("SshRemoteClient lost")));
         };
 
-        cx.spawn(|mut cx| {
-            let this = this.clone();
-            async move {
+        cx.spawn(async move |cx| {
                 let mut missed_heartbeats = 0;
 
                 let keepalive_timer = cx.background_executor().timer(HEARTBEAT_INTERVAL).fuse();
@@ -926,7 +923,7 @@ impl SshRemoteClient {
 
                             if missed_heartbeats != 0 {
                                 missed_heartbeats = 0;
-                                this.update(&mut cx, |this, mut cx| {
+                                this.update(cx, |this, mut cx| {
                                     this.handle_heartbeat_result(missed_heartbeats, &mut cx)
                                 })?;
                             }
@@ -957,7 +954,7 @@ impl SshRemoteClient {
                                 continue;
                             }
 
-                            let result = this.update(&mut cx, |this, mut cx| {
+                            let result = this.update(cx, |this, mut cx| {
                                 this.handle_heartbeat_result(missed_heartbeats, &mut cx)
                             })?;
                             if result.is_break() {
@@ -968,7 +965,7 @@ impl SshRemoteClient {
 
                     keepalive_timer.set(cx.background_executor().timer(HEARTBEAT_INTERVAL).fuse());
                 }
-            }
+
         })
     }
 
@@ -1006,7 +1003,7 @@ impl SshRemoteClient {
         io_task: Task<Result<i32>>,
         cx: &AsyncApp,
     ) -> Task<Result<()>> {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let result = io_task.await;
 
             match result {
@@ -1015,21 +1012,21 @@ impl SshRemoteClient {
                         match error {
                             ProxyLaunchError::ServerNotRunning => {
                                 log::error!("failed to reconnect because server is not running");
-                                this.update(&mut cx, |this, cx| {
+                                this.update(cx, |this, cx| {
                                     this.set_state(State::ServerNotRunning, cx);
                                 })?;
                             }
                         }
                     } else if exit_code > 0 {
                         log::error!("proxy process terminated unexpectedly");
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             this.reconnect(cx).ok();
                         })?;
                     }
                 }
                 Err(error) => {
                     log::warn!("ssh io task died with error: {:?}. reconnecting...", error);
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.reconnect(cx).ok();
                     })?;
                 }
@@ -1118,7 +1115,7 @@ impl SshRemoteClient {
     #[cfg(any(test, feature = "test-support"))]
     pub fn simulate_disconnect(&self, client_cx: &mut App) -> Task<()> {
         let opts = self.connection_options();
-        client_cx.spawn(|cx| async move {
+        client_cx.spawn(async move |cx| {
             let connection = cx
                 .update_global(|c: &mut ConnectionPool, _| {
                     if let Some(ConnectionPoolEntry::Connecting(c)) = c.connections.get(&opts) {
@@ -1220,8 +1217,8 @@ impl ConnectionPool {
         match connection {
             Some(ConnectionPoolEntry::Connecting(task)) => {
                 let delegate = delegate.clone();
-                cx.spawn(|mut cx| async move {
-                    delegate.set_status(Some("Waiting for existing connection attempt"), &mut cx);
+                cx.spawn(async move |cx| {
+                    delegate.set_status(Some("Waiting for existing connection attempt"), cx);
                 })
                 .detach();
                 return task.clone();
@@ -1241,8 +1238,8 @@ impl ConnectionPool {
             .spawn({
                 let opts = opts.clone();
                 let delegate = delegate.clone();
-                |mut cx| async move {
-                    let connection = SshRemoteConnection::new(opts.clone(), delegate, &mut cx)
+                async move |cx| {
+                    let connection = SshRemoteConnection::new(opts.clone(), delegate, cx)
                         .await
                         .map(|connection| Arc::new(connection) as Arc<dyn RemoteConnection>);
 
@@ -1676,7 +1673,7 @@ impl SshRemoteConnection {
             }
         });
 
-        cx.spawn(|_| async move {
+        cx.spawn(async move |_| {
             let result = futures::select! {
                 result = stdin_task.fuse() => {
                     result.context("stdin")
@@ -2102,7 +2099,7 @@ impl ChannelClient {
         mut incoming_rx: mpsc::UnboundedReceiver<Envelope>,
         cx: &AsyncApp,
     ) -> Task<Result<()>> {
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             let peer_id = PeerId { owner_id: 0, id: 0 };
             while let Some(incoming) = incoming_rx.next().await {
                 let Some(this) = this.upgrade() else {

crates/remote_server/src/headless_project.rs 🔗

@@ -406,8 +406,8 @@ impl HeadlessProject {
         // and immediately dropping the reference of the new client, causing it
         // to be dropped on the headless project, and the client only then
         // receiving a response to AddWorktree.
-        cx.spawn(|mut cx| async move {
-            this.update(&mut cx, |this, cx| {
+        cx.spawn(async move |cx| {
+            this.update(cx, |this, cx| {
                 this.worktree_store.update(cx, |worktree_store, cx| {
                     worktree_store.add(&worktree, cx);
                 });
@@ -636,7 +636,7 @@ impl HeadlessProject {
         _envelope: TypedEnvelope<proto::ShutdownRemoteServer>,
         cx: AsyncApp,
     ) -> Result<proto::Ack> {
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             cx.update(|cx| {
                 // TODO: This is a hack, because in a headless project, shutdown isn't executed
                 // when calling quit, but it should be.

crates/remote_server/src/unix.rs 🔗

@@ -272,7 +272,7 @@ fn start_server(
     })
     .detach();
 
-    cx.spawn(|cx| async move {
+    cx.spawn(async move |cx| {
         let mut stdin_incoming = listeners.stdin.incoming();
         let mut stdout_incoming = listeners.stdout.incoming();
         let mut stderr_incoming = listeners.stderr.incoming();
@@ -827,7 +827,7 @@ pub fn handle_settings_file_changes(
             .set_server_settings(&server_settings_content, cx)
             .log_err();
     });
-    cx.spawn(move |cx| async move {
+    cx.spawn(async move |cx| {
         while let Some(server_settings_content) = server_settings_file.next().await {
             let result = cx.update_global(|store: &mut SettingsStore, cx| {
                 let result = store.set_server_settings(&server_settings_content, cx);

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

@@ -118,7 +118,7 @@ impl NativeRunningKernel {
         window: &mut Window,
         cx: &mut App,
     ) -> Task<Result<Box<dyn RunningKernel>>> {
-        window.spawn(cx, |cx| async move {
+        window.spawn(cx, async move |cx| {
             let ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
             let ports = peek_ports(ip).await?;
 
@@ -177,10 +177,10 @@ impl NativeRunningKernel {
             cx.spawn({
                 let session = session.clone();
 
-                |mut cx| async move {
+                async move |cx| {
                     while let Some(message) = messages_rx.next().await {
                         session
-                            .update_in(&mut cx, |session, window, cx| {
+                            .update_in(cx, |session, window, cx| {
                                 session.route(&message, window, cx);
                             })
                             .ok();
@@ -194,10 +194,10 @@ impl NativeRunningKernel {
             cx.spawn({
                 let session = session.clone();
 
-                |mut cx| async move {
+                async move |cx| {
                     while let Ok(message) = iopub_socket.read().await {
                         session
-                            .update_in(&mut cx, |session, window, cx| {
+                            .update_in(cx, |session, window, cx| {
                                 session.route(&message, window, cx);
                             })
                             .ok();
@@ -253,7 +253,7 @@ impl NativeRunningKernel {
 
             let stderr = process.stderr.take();
 
-            cx.spawn(|mut _cx| async move {
+            cx.spawn(async move |_cx| {
                 if stderr.is_none() {
                     return;
                 }
@@ -267,7 +267,7 @@ impl NativeRunningKernel {
 
             let stdout = process.stdout.take();
 
-            cx.spawn(|mut _cx| async move {
+            cx.spawn(async move |_cx| {
                 if stdout.is_none() {
                     return;
                 }
@@ -281,7 +281,7 @@ impl NativeRunningKernel {
 
             let status = process.status();
 
-            let process_status_task = cx.spawn(|mut cx| async move {
+            let process_status_task = cx.spawn(async move |cx| {
                 let error_message = match status.await {
                     Ok(status) => {
                         if status.success() {
@@ -299,7 +299,7 @@ impl NativeRunningKernel {
                 log::error!("{}", error_message);
 
                 session
-                    .update(&mut cx, |session, cx| {
+                    .update(cx, |session, cx| {
                         session.kernel_errored(error_message, cx);
 
                         cx.notify();

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

@@ -148,7 +148,7 @@ impl RemoteRunningKernel {
 
         let http_client = cx.http_client();
 
-        window.spawn(cx, |cx| async move {
+        window.spawn(cx, async move |cx| {
             let kernel_id = launch_remote_kernel(
                 &remote_server,
                 http_client.clone(),
@@ -201,12 +201,12 @@ impl RemoteRunningKernel {
             let receiving_task = cx.spawn({
                 let session = session.clone();
 
-                |mut cx| async move {
+                async move |cx| {
                     while let Some(message) = r.next().await {
                         match message {
                             Ok(message) => {
                                 session
-                                    .update_in(&mut cx, |session, window, cx| {
+                                    .update_in(cx, |session, window, cx| {
                                         session.route(&message, window, cx);
                                     })
                                     .ok();
@@ -281,7 +281,7 @@ impl RunningKernel for RemoteRunningKernel {
         let token = self.remote_server.token.clone();
         let http_client = self.http_client.clone();
 
-        window.spawn(cx, |_| async move {
+        window.spawn(cx, async move |_| {
             let request = Request::builder()
                 .method("DELETE")
                 .uri(&url)

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

@@ -132,14 +132,14 @@ impl Cell {
                         let languages = languages.clone();
                         let source = source.clone();
 
-                        cx.spawn_in(window, |this, mut cx| async move {
+                        cx.spawn_in(window, async move |this, cx| {
                             let parsed_markdown = cx
                                 .background_spawn(async move {
                                     parse_markdown(&source, None, Some(languages)).await
                                 })
                                 .await;
 
-                            this.update(&mut cx, |cell: &mut MarkdownCell, _| {
+                            this.update(cx, |cell: &mut MarkdownCell, _| {
                                 cell.parsed_markdown = Some(parsed_markdown);
                             })
                             .log_err();
@@ -200,10 +200,10 @@ impl Cell {
                 });
 
                 let buffer = buffer.clone();
-                let language_task = cx.spawn_in(window, |this, mut cx| async move {
+                let language_task = cx.spawn_in(window, async move |this, cx| {
                     let language = notebook_language.await;
 
-                    buffer.update(&mut cx, |buffer, cx| {
+                    buffer.update(cx, |buffer, cx| {
                         buffer.set_language(language.clone(), cx);
                     });
                 });

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

@@ -92,7 +92,9 @@ impl NotebookEditor {
         let language_name = notebook_item.read(cx).language_name();
 
         let notebook_language = notebook_item.read(cx).notebook_language();
-        let notebook_language = cx.spawn_in(window, |_, _| notebook_language).shared();
+        let notebook_language = cx
+            .spawn_in(window, async move |_, _| notebook_language.await)
+            .shared();
 
         let mut cell_order = vec![]; // Vec<CellId>
         let mut cell_map = HashMap::default(); // HashMap<CellId, Cell>
@@ -570,9 +572,9 @@ impl project::ProjectItem for NotebookItem {
         let languages = project.read(cx).languages().clone();
 
         if path.path.extension().unwrap_or_default() == "ipynb" {
-            Some(cx.spawn(|mut cx| async move {
+            Some(cx.spawn(async move |cx| {
                 let abs_path = project
-                    .read_with(&cx, |project, cx| project.absolute_path(&path, cx))?
+                    .read_with(cx, |project, cx| project.absolute_path(&path, cx))?
                     .ok_or_else(|| anyhow::anyhow!("Failed to find the absolute path"))?;
 
                 // todo: watch for changes to the file
@@ -595,7 +597,7 @@ impl project::ProjectItem for NotebookItem {
                 };
 
                 let id = project
-                    .update(&mut cx, |project, cx| project.entry_for_path(&path, cx))?
+                    .update(cx, |project, cx| project.entry_for_path(&path, cx))?
                     .context("Entry not found")?
                     .id;
 

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

@@ -17,20 +17,18 @@ pub struct MarkdownView {
 
 impl MarkdownView {
     pub fn from(text: String, cx: &mut Context<Self>) -> Self {
-        let task = cx.spawn(|markdown_view, mut cx| {
+        let parsed = {
             let text = text.clone();
-            let parsed =
-                cx.background_spawn(async move { parse_markdown(&text, None, None).await });
-
-            async move {
-                let content = parsed.await;
+            cx.background_spawn(async move { parse_markdown(&text.clone(), None, None).await })
+        };
+        let task = cx.spawn(async move |markdown_view, cx| {
+            let content = parsed.await;
 
-                markdown_view.update(&mut cx, |markdown, cx| {
-                    markdown.parsing_markdown_task.take();
-                    markdown.contents = Some(content);
-                    cx.notify();
-                })
-            }
+            markdown_view.update(cx, |markdown, cx| {
+                markdown.parsing_markdown_task.take();
+                markdown.contents = Some(content);
+                cx.notify();
+            })
         });
 
         Self {

crates/repl/src/repl_store.rs 🔗

@@ -122,12 +122,12 @@ impl ReplStore {
         cx: &mut Context<Self>,
     ) -> Task<Result<()>> {
         let kernel_specifications = python_env_kernel_specifications(project, worktree_id, cx);
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let kernel_specifications = kernel_specifications
                 .await
                 .map_err(|e| anyhow::anyhow!("Failed to get python kernelspecs: {:?}", e))?;
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.kernel_specifications_for_worktree
                     .insert(worktree_id, kernel_specifications);
                 cx.notify();
@@ -149,7 +149,7 @@ impl ReplStore {
                     token,
                 };
                 let http_client = cx.http_client();
-                Some(cx.spawn(|_, _| async move {
+                Some(cx.spawn(async move |_, _| {
                     list_remote_kernelspecs(remote_server, http_client)
                         .await
                         .map(|specs| specs.into_iter().map(KernelSpecification::Remote).collect())
@@ -180,11 +180,11 @@ impl ReplStore {
             anyhow::Ok(all_specs)
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let all_specs = all_specs.await;
 
             if let Ok(specs) = all_specs {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.kernel_specifications = specs;
                     cx.notify();
                 })

crates/repl/src/session.rs 🔗

@@ -268,18 +268,18 @@ impl Session {
         };
 
         let pending_kernel = cx
-            .spawn(|this, mut cx| async move {
+            .spawn(async move |this, cx| {
                 let kernel = kernel.await;
 
                 match kernel {
                     Ok(kernel) => {
-                        this.update(&mut cx, |session, cx| {
+                        this.update(cx, |session, cx| {
                             session.kernel(Kernel::RunningKernel(kernel), cx);
                         })
                         .ok();
                     }
                     Err(err) => {
-                        this.update(&mut cx, |session, cx| {
+                        this.update(cx, |session, cx| {
                             session.kernel_errored(err.to_string(), cx);
                         })
                         .ok();
@@ -463,9 +463,9 @@ impl Session {
                 let task = task.clone();
                 let message = message.clone();
 
-                cx.spawn(|this, mut cx| async move {
+                cx.spawn(async move |this, cx| {
                     task.await;
-                    this.update(&mut cx, |session, cx| {
+                    this.update(cx, |session, cx| {
                         session.send(message, cx).ok();
                     })
                     .ok();
@@ -573,7 +573,7 @@ impl Session {
 
                 let forced = kernel.force_shutdown(window, cx);
 
-                cx.spawn(|this, mut cx| async move {
+                cx.spawn(async move |this, cx| {
                     let message: JupyterMessage = ShutdownRequest { restart: false }.into();
                     request_tx.try_send(message).ok();
 
@@ -582,7 +582,7 @@ impl Session {
                     // Give the kernel a bit of time to clean up
                     cx.background_executor().timer(Duration::from_secs(3)).await;
 
-                    this.update(&mut cx, |session, cx| {
+                    this.update(cx, |session, cx| {
                         session.clear_outputs(cx);
                         session.kernel(Kernel::Shutdown, cx);
                         cx.notify();
@@ -610,7 +610,7 @@ impl Session {
 
                 let forced = kernel.force_shutdown(window, cx);
 
-                cx.spawn_in(window, |this, mut cx| async move {
+                cx.spawn_in(window, async move |this, cx| {
                     // Send shutdown request with restart flag
                     log::debug!("restarting kernel");
                     let message: JupyterMessage = ShutdownRequest { restart: true }.into();
@@ -623,7 +623,7 @@ impl Session {
                     forced.await.log_err();
 
                     // Start a new kernel
-                    this.update_in(&mut cx, |session, window, cx| {
+                    this.update_in(cx, |session, window, cx| {
                         // TODO: Differentiate between restart and restart+clear-outputs
                         session.clear_outputs(cx);
                         session.start_kernel(window, cx);

crates/reqwest_client/examples/client.rs 🔗

@@ -10,7 +10,7 @@ use smol::stream::StreamExt;
 fn main() {
     let app = gpui::Application::new();
     app.run(|cx| {
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             let client = ReqwestClient::new();
             let start = Instant::now();
             let requests = [

crates/scripting_tool/src/scripting_session.rs 🔗

@@ -40,7 +40,7 @@ impl ScriptingSession {
             scripts: Vec::new(),
             changes_by_buffer: HashMap::default(),
             foreground_fns_tx,
-            _invoke_foreground_fns: cx.spawn(|this, cx| async move {
+            _invoke_foreground_fns: cx.spawn(async move |this, cx| {
                 while let Some(foreground_fn) = foreground_fns_rx.next().await {
                     foreground_fn.0(this.clone(), cx.clone());
                 }
@@ -70,11 +70,11 @@ impl ScriptingSession {
 
         let task = self.run_lua(script_src, stdout, cx);
 
-        let task = cx.spawn(|session, mut cx| async move {
+        let task = cx.spawn(async move |session, cx| {
             let result = task.await;
 
             session
-                .update(&mut cx, |session, _cx| {
+                .update(cx, |session, _cx| {
                     let script = session.get_mut(id);
                     let stdout = script.stdout_snapshot();
 
@@ -333,10 +333,10 @@ impl ScriptingSession {
                         .project
                         .update(cx, |project, cx| project.open_buffer(project_path, cx));
 
-                    cx.spawn(|_, cx| async move {
+                    cx.spawn(async move |_, cx| {
                         let buffer = open_buffer_task.await?;
 
-                        let text = buffer.read_with(&cx, |buffer, _cx| buffer.text())?;
+                        let text = buffer.read_with(cx, |buffer, _cx| buffer.text())?;
                         Ok(text)
                     })
                 })
@@ -384,14 +384,12 @@ impl ScriptingSession {
                         .project
                         .update(cx, |project, cx| project.open_buffer(project_path, cx));
 
-                    cx.spawn(move |session, mut cx| async move {
+                    cx.spawn(async move |session, cx| {
                         let buffer = open_buffer_task.await?;
 
-                        let diff = buffer
-                            .update(&mut cx, |buffer, cx| buffer.diff(text, cx))?
-                            .await;
+                        let diff = buffer.update(cx, |buffer, cx| buffer.diff(text, cx))?.await;
 
-                        let edit_ids = buffer.update(&mut cx, |buffer, cx| {
+                        let edit_ids = buffer.update(cx, |buffer, cx| {
                             buffer.finalize_last_transaction();
                             buffer.apply_diff(diff, cx);
                             let transaction = buffer.finalize_last_transaction();
@@ -400,7 +398,7 @@ impl ScriptingSession {
                         })?;
 
                         session
-                            .update(&mut cx, {
+                            .update(cx, {
                                 let buffer = buffer.clone();
 
                                 |session, cx| {
@@ -411,13 +409,13 @@ impl ScriptingSession {
                             })?
                             .await?;
 
-                        let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot())?;
+                        let snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
 
                         // If we saved successfully, mark buffer as changed
                         let buffer_without_changes =
-                            buffer.update(&mut cx, |buffer, cx| buffer.branch(cx))?;
+                            buffer.update(cx, |buffer, cx| buffer.branch(cx))?;
                         session
-                            .update(&mut cx, |session, cx| {
+                            .update(cx, |session, cx| {
                                 let changed_buffer = session
                                     .changes_by_buffer
                                     .entry(buffer)
@@ -757,11 +755,11 @@ impl ScriptingSession {
                                 cx,
                             );
                             let (abs_paths_tx, abs_paths_rx) = mpsc::unbounded();
-                            cx.spawn(|worktree_store, cx| async move {
+                            cx.spawn(async move |worktree_store, cx| {
                                 pin_mut!(candidates);
 
                                 while let Some(project_path) = candidates.next().await {
-                                    worktree_store.read_with(&cx, |worktree_store, cx| {
+                                    worktree_store.read_with(cx, |worktree_store, cx| {
                                         if let Some(worktree) = worktree_store
                                             .worktree_for_id(project_path.worktree_id, cx)
                                         {
@@ -800,17 +798,17 @@ impl ScriptingSession {
             "getting code outline",
             foreground_tx,
             Box::new(move |session, cx| {
-                cx.spawn(move |mut cx| async move {
+                cx.spawn(async move |cx| {
                     // TODO: This will not use file content from `fs_changes`. It will also reflect
                     // user changes that have not been saved.
                     let buffer = session
-                        .update(&mut cx, |session, cx| {
+                        .update(cx, |session, cx| {
                             session
                                 .project
                                 .update(cx, |project, cx| project.open_local_buffer(&path, cx))
                         })?
                         .await?;
-                    buffer.update(&mut cx, |buffer, _cx| {
+                    buffer.update(cx, |buffer, _cx| {
                         if let Some(outline) = buffer.snapshot().outline(None) {
                             Ok(outline)
                         } else {

crates/search/src/buffer_search.rs 🔗

@@ -693,13 +693,13 @@ impl BufferSearchBar {
                 query_buffer.set_language_registry(languages.clone());
             });
 
-            cx.spawn(|buffer_search_bar, mut cx| async move {
+            cx.spawn(async move |buffer_search_bar, cx| {
                 let regex_language = languages
                     .language_for_name("regex")
                     .await
                     .context("loading regex language")?;
                 buffer_search_bar
-                    .update(&mut cx, |buffer_search_bar, cx| {
+                    .update(cx, |buffer_search_bar, cx| {
                         buffer_search_bar.regex_language = Some(regex_language);
                         buffer_search_bar.adjust_query_regex_language(cx);
                     })
@@ -848,9 +848,9 @@ impl BufferSearchBar {
             .map(|suggestion| self.search(&suggestion, Some(self.default_options), window, cx));
 
         if let Some(search) = search {
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 search.await?;
-                this.update_in(&mut cx, |this, window, cx| {
+                this.update_in(cx, |this, window, cx| {
                     this.activate_current_match(window, cx)
                 })
             })
@@ -1097,9 +1097,9 @@ impl BufferSearchBar {
                 self.editor_needed_width = width;
                 cx.notify();
 
-                cx.spawn_in(window, |this, mut cx| async move {
+                cx.spawn_in(window, async move |this, cx| {
                     search.await?;
-                    this.update_in(&mut cx, |this, window, cx| {
+                    this.update_in(cx, |this, window, cx| {
                         this.activate_current_match(window, cx)
                     })
                 })
@@ -1271,10 +1271,10 @@ impl BufferSearchBar {
                 let matches = active_searchable_item.find_matches(query, window, cx);
 
                 let active_searchable_item = active_searchable_item.downgrade();
-                self.pending_search = Some(cx.spawn_in(window, |this, mut cx| async move {
+                self.pending_search = Some(cx.spawn_in(window, async move |this, cx| {
                     let matches = matches.await;
 
-                    this.update_in(&mut cx, |this, window, cx| {
+                    this.update_in(cx, |this, window, cx| {
                         if let Some(active_searchable_item) =
                             WeakSearchableItemHandle::upgrade(active_searchable_item.as_ref(), cx)
                         {

crates/search/src/project_search.rs 🔗

@@ -260,10 +260,10 @@ impl ProjectSearch {
         self.search_id += 1;
         self.active_query = Some(query);
         self.match_ranges.clear();
-        self.pending_search = Some(cx.spawn(|this, mut cx| async move {
+        self.pending_search = Some(cx.spawn(async move |this, cx| {
             let mut matches = pin!(search.ready_chunks(1024));
             let this = this.upgrade()?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.match_ranges.clear();
                 this.excerpts.update(cx, |this, cx| this.clear(cx));
                 this.no_results = Some(true);
@@ -286,7 +286,7 @@ impl ProjectSearch {
                 }
 
                 let match_ranges = this
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         this.excerpts.update(cx, |excerpts, cx| {
                             excerpts.push_multiple_excerpts_with_context_lines(
                                 buffers_with_ranges,
@@ -298,14 +298,14 @@ impl ProjectSearch {
                     .ok()?
                     .await;
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.match_ranges.extend(match_ranges);
                     cx.notify();
                 })
                 .ok()?;
             }
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 if !this.match_ranges.is_empty() {
                     this.no_results = Some(false);
                 }
@@ -796,13 +796,13 @@ impl ProjectSearchView {
         }));
 
         let languages = project.read(cx).languages().clone();
-        cx.spawn(|project_search_view, mut cx| async move {
+        cx.spawn(async move |project_search_view, cx| {
             let regex_language = languages
                 .language_for_name("regex")
                 .await
                 .context("loading regex language")?;
             project_search_view
-                .update(&mut cx, |project_search_view, cx| {
+                .update(cx, |project_search_view, cx| {
                     project_search_view.regex_language = Some(regex_language);
                     project_search_view.adjust_query_regex_language(cx);
                 })

crates/semantic_index/examples/index.rs 🔗

@@ -55,18 +55,18 @@ fn main() {
             api_key,
         ));
 
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let semantic_index = SemanticDb::new(
                 PathBuf::from("/tmp/semantic-index-db.mdb"),
                 embedding_provider,
-                &mut cx,
+                cx,
             );
 
             let mut semantic_index = semantic_index.await.unwrap();
 
             let project_path = Path::new(&args[1]);
 
-            let project = Project::example([project_path], &mut cx).await;
+            let project = Project::example([project_path], cx).await;
 
             cx.update(|cx| {
                 let language_registry = project.read(cx).languages().clone();
@@ -113,7 +113,7 @@ fn main() {
                         let worktree = search_result.worktree.read(cx);
                         let entry_abs_path = worktree.abs_path().join(search_result.path.clone());
                         let fs = project.read(cx).fs().clone();
-                        cx.spawn(|_| async move { fs.load(&entry_abs_path).await.unwrap() })
+                        cx.spawn(async move |_| fs.load(&entry_abs_path).await.unwrap())
                     })
                     .unwrap()
                     .await;

crates/semantic_index/src/embedding_index.rs 🔗

@@ -229,7 +229,7 @@ impl EmbeddingIndex {
         let language_registry = self.language_registry.clone();
         let fs = self.fs.clone();
         let (chunked_files_tx, chunked_files_rx) = channel::bounded(2048);
-        let task = cx.spawn(|cx| async move {
+        let task = cx.spawn(async move |cx| {
             cx.background_executor()
                 .scoped(|cx| {
                     for _ in 0..cx.num_cpus() {

crates/semantic_index/src/project_index.rs 🔗

@@ -91,12 +91,9 @@ impl ProjectIndex {
             last_status: Status::Idle,
             embedding_provider,
             _subscription: cx.subscribe(&project, Self::handle_project_event),
-            _maintain_status: cx.spawn(|this, mut cx| async move {
+            _maintain_status: cx.spawn(async move |this, cx| {
                 while status_rx.recv().await.is_ok() {
-                    if this
-                        .update(&mut cx, |this, cx| this.update_status(cx))
-                        .is_err()
-                    {
+                    if this.update(cx, |this, cx| this.update_status(cx)).is_err() {
                         break;
                     }
                 }
@@ -163,10 +160,10 @@ impl ProjectIndex {
                     cx,
                 );
 
-                let load_worktree = cx.spawn(|this, mut cx| async move {
+                let load_worktree = cx.spawn(async move |this, cx| {
                     let result = match worktree_index.await {
                         Ok(worktree_index) => {
-                            this.update(&mut cx, |this, _| {
+                            this.update(cx, |this, _| {
                                 this.worktree_indices.insert(
                                     worktree_id,
                                     WorktreeIndexHandle::Loaded {
@@ -177,14 +174,14 @@ impl ProjectIndex {
                             Ok(worktree_index)
                         }
                         Err(error) => {
-                            this.update(&mut cx, |this, _cx| {
+                            this.update(cx, |this, _cx| {
                                 this.worktree_indices.remove(&worktree_id)
                             })?;
                             Err(Arc::new(error))
                         }
                     };
 
-                    this.update(&mut cx, |this, cx| this.update_status(cx))?;
+                    this.update(cx, |this, cx| this.update_status(cx))?;
 
                     result
                 });
@@ -239,7 +236,7 @@ impl ProjectIndex {
         for worktree_index in self.worktree_indices.values() {
             let worktree_index = worktree_index.clone();
             let chunks_tx = chunks_tx.clone();
-            worktree_scan_tasks.push(cx.spawn(|cx| async move {
+            worktree_scan_tasks.push(cx.spawn(async move |cx| {
                 let index = match worktree_index {
                     WorktreeIndexHandle::Loading { index } => {
                         index.clone().await.map_err(|error| anyhow!(error))?
@@ -248,7 +245,7 @@ impl ProjectIndex {
                 };
 
                 index
-                    .read_with(&cx, |index, cx| {
+                    .read_with(cx, |index, cx| {
                         let worktree_id = index.worktree().read(cx).id();
                         let db_connection = index.db_connection().clone();
                         let db = *index.embedding_index().db();
@@ -275,7 +272,7 @@ impl ProjectIndex {
 
         let project = self.project.clone();
         let embedding_provider = self.embedding_provider.clone();
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             #[cfg(debug_assertions)]
             let embedding_query_start = std::time::Instant::now();
             log::info!("Searching for {queries:?}");
@@ -336,7 +333,7 @@ impl ProjectIndex {
                 scan_task.log_err();
             }
 
-            project.read_with(&cx, |project, cx| {
+            project.read_with(cx, |project, cx| {
                 let mut search_results = Vec::with_capacity(results_by_worker.len() * limit);
                 for worker_results in results_by_worker {
                     search_results.extend(worker_results.into_iter().filter_map(|result| {
@@ -419,7 +416,7 @@ impl ProjectIndex {
         for worktree_index in self.worktree_indices.values() {
             let worktree_index = worktree_index.clone();
             let summaries_tx: channel::Sender<(String, String)> = summaries_tx.clone();
-            worktree_scan_tasks.push(cx.spawn(|cx| async move {
+            worktree_scan_tasks.push(cx.spawn(async move |cx| {
                 let index = match worktree_index {
                     WorktreeIndexHandle::Loading { index } => {
                         index.clone().await.map_err(|error| anyhow!(error))?
@@ -428,7 +425,7 @@ impl ProjectIndex {
                 };
 
                 index
-                    .read_with(&cx, |index, cx| {
+                    .read_with(cx, |index, cx| {
                         let db_connection = index.db_connection().clone();
                         let summary_index = index.summary_index();
                         let file_digest_db = summary_index.file_digest_db();
@@ -474,7 +471,7 @@ impl ProjectIndex {
         drop(summaries_tx);
 
         let project = self.project.clone();
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             let mut results_by_worker = Vec::new();
             for _ in 0..cx.background_executor().num_cpus() {
                 results_by_worker.push(Vec::<FileSummary>::new());
@@ -496,7 +493,7 @@ impl ProjectIndex {
                 scan_task.log_err();
             }
 
-            project.read_with(&cx, |_project, _cx| {
+            project.read_with(cx, |_project, _cx| {
                 results_by_worker.into_iter().flatten().collect()
             })
         })
@@ -509,7 +506,7 @@ impl ProjectIndex {
         futures::future::join_all(self.worktree_indices.values().map(|worktree_index| {
             let worktree_index = worktree_index.clone();
 
-            cx.spawn(|cx| async move {
+            cx.spawn(async move |cx| {
                 let index = match worktree_index {
                     WorktreeIndexHandle::Loading { index } => {
                         index.clone().await.map_err(|error| anyhow!(error))?
@@ -520,7 +517,7 @@ impl ProjectIndex {
                     cx.update(|cx| index.read(cx).worktree().read(cx).abs_path())?;
 
                 index
-                    .read_with(&cx, |index, cx| {
+                    .read_with(cx, |index, cx| {
                         cx.background_spawn(
                             index.summary_index().flush_backlog(worktree_abs_path, cx),
                         )

crates/semantic_index/src/project_index_debug_view.rs 🔗

@@ -51,12 +51,12 @@ impl ProjectIndexDebugView {
 
     fn update_rows(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         let worktree_indices = self.index.read(cx).worktree_indices(cx);
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let mut rows = Vec::new();
 
             for index in worktree_indices {
                 let (root_path, worktree_id, worktree_paths) =
-                    index.read_with(&cx, |index, cx| {
+                    index.read_with(cx, |index, cx| {
                         let worktree = index.worktree().read(cx);
                         (
                             worktree.abs_path(),
@@ -73,7 +73,7 @@ impl ProjectIndexDebugView {
                 );
             }
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.rows = rows;
                 cx.notify();
             })
@@ -96,7 +96,7 @@ impl ProjectIndexDebugView {
             .embedding_index()
             .chunks_for_path(file_path.clone(), cx);
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let chunks = chunks.await?;
             let content = fs.load(&root_path.join(&file_path)).await?;
             let chunks = chunks
@@ -114,7 +114,7 @@ impl ProjectIndexDebugView {
                 })
                 .collect::<Vec<_>>();
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let view = cx.entity().downgrade();
                 this.selected_path = Some(PathState {
                     path: file_path,

crates/semantic_index/src/summary_index.rs 🔗

@@ -422,7 +422,7 @@ impl SummaryIndex {
     ) -> MightNeedSummaryFiles {
         let fs = self.fs.clone();
         let (rx, tx) = channel::bounded(2048);
-        let task = cx.spawn(|cx| async move {
+        let task = cx.spawn(async move |cx| {
             cx.background_executor()
                 .scoped(|cx| {
                     for _ in 0..cx.num_cpus() {
@@ -490,7 +490,7 @@ impl SummaryIndex {
         cx: &App,
     ) -> SummarizeFiles {
         let (summarized_tx, summarized_rx) = channel::bounded(512);
-        let task = cx.spawn(|cx| async move {
+        let task = cx.spawn(async move |cx| {
             while let Ok(file) = unsummarized_files.recv().await {
                 log::debug!("Summarizing {:?}", file);
                 let summary = cx
@@ -564,7 +564,7 @@ impl SummaryIndex {
         };
 
         let code_len = code.len();
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             let stream = model.stream_completion(request, &cx);
             cx.background_spawn(async move {
                 let answer: String = stream

crates/semantic_index/src/worktree_index.rs 🔗

@@ -49,7 +49,7 @@ impl WorktreeIndex {
         let worktree_abs_path = worktree.read(cx).abs_path();
         let embedding_fs = Arc::clone(&fs);
         let summary_fs = fs;
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let entries_being_indexed = Arc::new(IndexingEntrySet::new(status_tx));
             let (embedding_index, summary_index) = cx
                 .background_spawn({
@@ -138,7 +138,9 @@ impl WorktreeIndex {
             summary_index,
             worktree,
             entry_ids_being_indexed,
-            _index_entries: cx.spawn(|this, cx| Self::index_entries(this, updated_entries_rx, cx)),
+            _index_entries: cx.spawn(async move |this, cx| {
+                Self::index_entries(this, updated_entries_rx, cx).await
+            }),
             _subscription,
         }
     }
@@ -166,10 +168,10 @@ impl WorktreeIndex {
     async fn index_entries(
         this: WeakEntity<Self>,
         updated_entries: channel::Receiver<UpdatedEntriesSet>,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<()> {
         let is_auto_available = cx.update(|cx| cx.wait_for_flag::<AutoCommand>())?.await;
-        let index = this.update(&mut cx, |this, cx| {
+        let index = this.update(cx, |this, cx| {
             futures::future::try_join(
                 this.embedding_index.index_entries_changed_on_disk(cx),
                 this.summary_index
@@ -183,7 +185,7 @@ impl WorktreeIndex {
                 .update(|cx| cx.has_flag::<AutoCommand>())
                 .unwrap_or(false);
 
-            let index = this.update(&mut cx, |this, cx| {
+            let index = this.update(cx, |this, cx| {
                 futures::future::try_join(
                     this.embedding_index
                         .index_updated_entries(updated_entries.clone(), cx),

crates/session/src/session.rs 🔗

@@ -67,16 +67,14 @@ impl AppSession {
     pub fn new(session: Session, cx: &Context<Self>) -> Self {
         let _subscriptions = vec![cx.on_app_quit(Self::app_will_quit)];
 
-        let _serialization_task = Some(cx.spawn(|_, cx| async move {
-            loop {
-                if let Some(windows) = cx.update(|cx| cx.window_stack()).ok().flatten() {
-                    store_window_stack(windows).await;
-                }
-
-                cx.background_executor()
-                    .timer(Duration::from_millis(100))
-                    .await;
+        let _serialization_task = Some(cx.spawn(async move |_, cx| loop {
+            if let Some(windows) = cx.update(|cx| cx.window_stack()).ok().flatten() {
+                store_window_stack(windows).await;
             }
+
+            cx.background_executor()
+                .timer(Duration::from_millis(100))
+                .await;
         }));
 
         Self {

crates/settings/src/settings_store.rs 🔗

@@ -263,7 +263,7 @@ impl SettingsStore {
             raw_editorconfig_settings: BTreeMap::default(),
             tab_size_callback: Default::default(),
             setting_file_updates_tx,
-            _setting_file_updates: cx.spawn(|cx| async move {
+            _setting_file_updates: cx.spawn(async move |cx| {
                 while let Some(setting_file_update) = setting_file_updates_rx.next().await {
                     (setting_file_update)(cx.clone()).await.log_err();
                 }

crates/snippet_provider/src/lib.rs 🔗

@@ -181,8 +181,8 @@ impl SnippetProvider {
     fn watch_directory(&mut self, path: &Path, cx: &Context<Self>) {
         let path: Arc<Path> = Arc::from(path);
 
-        self.watch_tasks.push(cx.spawn(|this, mut cx| async move {
-            let fs = this.update(&mut cx, |this, _| this.fs.clone())?;
+        self.watch_tasks.push(cx.spawn(async move |this, cx| {
+            let fs = this.update(cx, |this, _| this.fs.clone())?;
             let watched_path = path.clone();
             let watcher = fs.watch(&watched_path, Duration::from_secs(1));
             initial_scan(this.clone(), path, cx.clone()).await?;

crates/snippets_ui/src/snippets_ui.rs 🔗

@@ -134,13 +134,13 @@ impl PickerDelegate for ScopeSelectorDelegate {
             let language = self.language_registry.language_for_name(&scope_name);
 
             if let Some(workspace) = self.workspace.upgrade() {
-                cx.spawn_in(window, |_, mut cx| async move {
+                cx.spawn_in(window, async move |_, cx| {
                     let scope = match scope_name.as_str() {
                         "Global" => "snippets".to_string(),
                         _ => language.await?.lsp_id(),
                     };
 
-                    workspace.update_in(&mut cx, |workspace, window, cx| {
+                    workspace.update_in(cx, |workspace, window, cx| {
                         workspace
                             .open_abs_path(
                                 config_dir().join("snippets").join(scope + ".json"),
@@ -187,7 +187,7 @@ impl PickerDelegate for ScopeSelectorDelegate {
     ) -> gpui::Task<()> {
         let background = cx.background_executor().clone();
         let candidates = self.candidates.clone();
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let matches = if query.is_empty() {
                 candidates
                     .into_iter()
@@ -211,7 +211,7 @@ impl PickerDelegate for ScopeSelectorDelegate {
                 .await
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let delegate = &mut this.delegate;
                 delegate.matches = matches;
                 delegate.selected_index = delegate

crates/storybook/src/storybook.rs 🔗

@@ -152,7 +152,7 @@ pub fn init(cx: &mut App) {
 }
 
 fn quit(_: &Quit, cx: &mut App) {
-    cx.spawn(|cx| async move {
+    cx.spawn(async move |cx| {
         cx.update(|cx| cx.quit())?;
         anyhow::Ok(())
     })

crates/supermaven/src/supermaven.rs 🔗

@@ -87,11 +87,11 @@ impl Supermaven {
 
     pub fn start(&mut self, client: Arc<Client>, cx: &mut Context<Self>) {
         if let Self::Starting = self {
-            cx.spawn(|this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 let binary_path =
                     supermaven_api::get_supermaven_agent_path(client.http_client()).await?;
 
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     if let Self::Starting = this {
                         *this =
                             Self::Spawned(SupermavenAgent::new(binary_path, client.clone(), cx)?);
@@ -290,7 +290,7 @@ impl SupermavenAgent {
         cx.spawn({
             let client = client.clone();
             let outgoing_tx = outgoing_tx.clone();
-            move |this, mut cx| async move {
+            async move |this, cx| {
                 let mut status = client.status();
                 while let Some(status) = status.next().await {
                     if status.is_connected() {
@@ -298,7 +298,7 @@ impl SupermavenAgent {
                         outgoing_tx
                             .unbounded_send(OutboundMessage::SetApiKey(SetApiKey { api_key }))
                             .ok();
-                        this.update(&mut cx, |this, cx| {
+                        this.update(cx, |this, cx| {
                             if let Supermaven::Spawned(this) = this {
                                 this.account_status = AccountStatus::Ready;
                                 cx.notify();
@@ -317,10 +317,12 @@ impl SupermavenAgent {
             next_state_id: SupermavenCompletionStateId::default(),
             states: BTreeMap::default(),
             outgoing_tx,
-            _handle_outgoing_messages: cx
-                .spawn(|_, _cx| Self::handle_outgoing_messages(outgoing_rx, stdin)),
-            _handle_incoming_messages: cx
-                .spawn(|this, cx| Self::handle_incoming_messages(this, stdout, cx)),
+            _handle_outgoing_messages: cx.spawn(async move |_, _cx| {
+                Self::handle_outgoing_messages(outgoing_rx, stdin).await
+            }),
+            _handle_incoming_messages: cx.spawn(async move |this, cx| {
+                Self::handle_incoming_messages(this, stdout, cx).await
+            }),
             account_status: AccountStatus::Unknown,
             service_tier: None,
             client,
@@ -342,7 +344,7 @@ impl SupermavenAgent {
     async fn handle_incoming_messages(
         this: WeakEntity<Supermaven>,
         stdout: ChildStdout,
-        mut cx: AsyncApp,
+        cx: &mut AsyncApp,
     ) -> Result<()> {
         const MESSAGE_PREFIX: &str = "SM-MESSAGE ";
 
@@ -362,7 +364,7 @@ impl SupermavenAgent {
                 continue;
             };
 
-            this.update(&mut cx, |this, _cx| {
+            this.update(cx, |this, _cx| {
                 if let Supermaven::Spawned(this) = this {
                     this.handle_message(message);
                 }

crates/supermaven/src/supermaven_completion_provider.rs 🔗

@@ -133,13 +133,13 @@ impl EditPredictionProvider for SupermavenCompletionProvider {
             return;
         };
 
-        self.pending_refresh = Some(cx.spawn(|this, mut cx| async move {
+        self.pending_refresh = Some(cx.spawn(async move |this, cx| {
             if debounce {
                 cx.background_executor().timer(DEBOUNCE_TIMEOUT).await;
             }
 
             while let Some(()) = completion.updates.next().await {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     this.completion_id = Some(completion.id);
                     this.buffer_id = Some(buffer_handle.entity_id());
                     this.file_extension = buffer_handle.read(cx).file().and_then(|file| {

crates/tasks_ui/src/modal.rs 🔗

@@ -217,40 +217,36 @@ impl PickerDelegate for TasksModalDelegate {
         cx: &mut Context<picker::Picker<Self>>,
     ) -> Task<()> {
         let task_type = self.task_modal_type.clone();
-        cx.spawn_in(window, move |picker, mut cx| async move {
+        cx.spawn_in(window, async move |picker, cx| {
             let Some(candidates) = picker
-                .update(&mut cx, |picker, cx| {
-                    match &mut picker.delegate.candidates {
-                        Some(candidates) => string_match_candidates(candidates.iter(), task_type),
-                        None => {
-                            let Some(task_inventory) = picker
-                                .delegate
-                                .task_store
-                                .read(cx)
-                                .task_inventory()
-                                .cloned()
-                            else {
-                                return Vec::new();
-                            };
+                .update(cx, |picker, cx| match &mut picker.delegate.candidates {
+                    Some(candidates) => string_match_candidates(candidates.iter(), task_type),
+                    None => {
+                        let Some(task_inventory) = picker
+                            .delegate
+                            .task_store
+                            .read(cx)
+                            .task_inventory()
+                            .cloned()
+                        else {
+                            return Vec::new();
+                        };
 
-                            let (used, current) =
-                                task_inventory.read(cx).used_and_current_resolved_tasks(
-                                    &picker.delegate.task_contexts,
-                                    cx,
-                                );
-                            picker.delegate.last_used_candidate_index = if used.is_empty() {
-                                None
-                            } else {
-                                Some(used.len() - 1)
-                            };
+                        let (used, current) = task_inventory
+                            .read(cx)
+                            .used_and_current_resolved_tasks(&picker.delegate.task_contexts, cx);
+                        picker.delegate.last_used_candidate_index = if used.is_empty() {
+                            None
+                        } else {
+                            Some(used.len() - 1)
+                        };
 
-                            let mut new_candidates = used;
-                            new_candidates.extend(current);
-                            let match_candidates =
-                                string_match_candidates(new_candidates.iter(), task_type);
-                            let _ = picker.delegate.candidates.insert(new_candidates);
-                            match_candidates
-                        }
+                        let mut new_candidates = used;
+                        new_candidates.extend(current);
+                        let match_candidates =
+                            string_match_candidates(new_candidates.iter(), task_type);
+                        let _ = picker.delegate.candidates.insert(new_candidates);
+                        match_candidates
                     }
                 })
                 .ok()
@@ -267,7 +263,7 @@ impl PickerDelegate for TasksModalDelegate {
             )
             .await;
             picker
-                .update(&mut cx, |picker, _| {
+                .update(cx, |picker, _| {
                     let delegate = &mut picker.delegate;
                     delegate.matches = matches;
                     if let Some(index) = delegate.last_used_candidate_index {

crates/tasks_ui/src/tasks_ui.rs 🔗

@@ -48,11 +48,11 @@ pub fn init(cx: &mut App) {
                                 original_task.use_new_terminal = use_new_terminal;
                             }
                             let task_contexts = task_contexts(workspace, window, cx);
-                            cx.spawn_in(window, |workspace, mut cx| async move {
+                            cx.spawn_in(window, async move |workspace, cx| {
                                 let task_contexts = task_contexts.await;
                                 let default_context = TaskContext::default();
                                 workspace
-                                    .update_in(&mut cx, |workspace, _, cx| {
+                                    .update_in(cx, |workspace, _, cx| {
                                         schedule_task(
                                             workspace,
                                             task_source_kind,
@@ -146,10 +146,10 @@ pub fn toggle_modal(
     });
     if can_open_modal {
         let task_contexts = task_contexts(workspace, window, cx);
-        cx.spawn_in(window, |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             let task_contexts = task_contexts.await;
             workspace
-                .update_in(&mut cx, |workspace, window, cx| {
+                .update_in(cx, |workspace, window, cx| {
                     workspace.toggle_modal(window, cx, |window, cx| {
                         TasksModal::new(
                             task_store.clone(),
@@ -177,12 +177,12 @@ fn spawn_task_with_name(
     window: &mut Window,
     cx: &mut Context<Workspace>,
 ) -> Task<anyhow::Result<()>> {
-    cx.spawn_in(window, |workspace, mut cx| async move {
-        let task_contexts = workspace.update_in(&mut cx, |workspace, window, cx| {
+    cx.spawn_in(window, async move |workspace, cx| {
+        let task_contexts = workspace.update_in(cx, |workspace, window, cx| {
             task_contexts(workspace, window, cx)
         })?;
         let task_contexts = task_contexts.await;
-        let tasks = workspace.update(&mut cx, |workspace, cx| {
+        let tasks = workspace.update(cx, |workspace, cx| {
             let Some(task_inventory) = workspace
                 .project()
                 .read(cx)
@@ -209,7 +209,7 @@ fn spawn_task_with_name(
         })?;
 
         let did_spawn = workspace
-            .update(&mut cx, |workspace, cx| {
+            .update(cx, |workspace, cx| {
                 let (task_source_kind, mut target_task) =
                     tasks.into_iter().find(|(_, task)| task.label == name)?;
                 if let Some(overrides) = &overrides {
@@ -232,7 +232,7 @@ fn spawn_task_with_name(
             .is_some();
         if !did_spawn {
             workspace
-                .update_in(&mut cx, |workspace, window, cx| {
+                .update_in(cx, |workspace, window, cx| {
                     spawn_task_or_modal(
                         workspace,
                         &Spawn::ViaModal {

crates/terminal/src/terminal.rs 🔗

@@ -487,9 +487,9 @@ impl TerminalBuilder {
 
     pub fn subscribe(mut self, cx: &Context<Terminal>) -> Terminal {
         //Event loop
-        cx.spawn(|terminal, mut cx| async move {
+        cx.spawn(async move |terminal, cx| {
             while let Some(event) = self.events_rx.next().await {
-                terminal.update(&mut cx, |terminal, cx| {
+                terminal.update(cx, |terminal, cx| {
                     //Process the first event immediately for lowered latency
                     terminal.process_event(&event, cx);
                 })?;
@@ -527,7 +527,7 @@ impl TerminalBuilder {
                         break 'outer;
                     }
 
-                    terminal.update(&mut cx, |this, cx| {
+                    terminal.update(cx, |this, cx| {
                         if wakeup {
                             this.process_event(&AlacTermEvent::Wakeup, cx);
                         }
@@ -1814,7 +1814,7 @@ impl Terminal {
         if let Some(task) = self.task() {
             if task.status == TaskStatus::Running {
                 let completion_receiver = task.completion_rx.clone();
-                return cx.spawn(|_| async move {
+                return cx.spawn(async move |_| {
                     let _ = completion_receiver.recv().await;
                 });
             }

crates/terminal_view/src/persistence.rs 🔗

@@ -90,8 +90,8 @@ pub(crate) fn deserialize_terminal_panel(
     window: &mut Window,
     cx: &mut App,
 ) -> Task<anyhow::Result<Entity<TerminalPanel>>> {
-    window.spawn(cx, move |mut cx| async move {
-        let terminal_panel = workspace.update_in(&mut cx, |workspace, window, cx| {
+    window.spawn(cx, async move |cx| {
+        let terminal_panel = workspace.update_in(cx, |workspace, window, cx| {
             cx.new(|cx| {
                 let mut panel = TerminalPanel::new(workspace, window, cx);
                 panel.height = serialized_panel.height.map(|h| h.round());
@@ -106,11 +106,11 @@ pub(crate) fn deserialize_terminal_panel(
                     project,
                     workspace,
                     item_ids.as_slice(),
-                    &mut cx,
+                    cx,
                 )
                 .await;
                 let active_item = serialized_panel.active_item_id;
-                terminal_panel.update_in(&mut cx, |terminal_panel, window, cx| {
+                terminal_panel.update_in(cx, |terminal_panel, window, cx| {
                     terminal_panel.active_pane.update(cx, |pane, cx| {
                         populate_pane_items(pane, items, active_item, window, cx);
                     });
@@ -123,11 +123,11 @@ pub(crate) fn deserialize_terminal_panel(
                     terminal_panel.clone(),
                     database_id,
                     serialized_pane_group,
-                    &mut cx,
+                    cx,
                 )
                 .await;
                 if let Some((center_group, active_pane)) = center_pane {
-                    terminal_panel.update(&mut cx, |terminal_panel, _| {
+                    terminal_panel.update(cx, |terminal_panel, _| {
                         terminal_panel.center = PaneGroup::with_root(center_group);
                         terminal_panel.active_pane =
                             active_pane.unwrap_or_else(|| terminal_panel.center.first_pane());

crates/terminal_view/src/terminal_panel.rs 🔗

@@ -232,7 +232,7 @@ impl TerminalPanel {
         let mut terminal_panel = None;
 
         match workspace
-            .read_with(&mut cx, |workspace, _| {
+            .read_with(&cx, |workspace, _| {
                 workspace
                     .database_id()
                     .zip(TerminalPanel::serialization_key(workspace))
@@ -535,9 +535,9 @@ impl TerminalPanel {
 
         self.deferred_tasks.insert(
             task.id.clone(),
-            cx.spawn_in(window, |terminal_panel, mut cx| async move {
-                wait_for_terminals_tasks(terminals_for_task, &mut cx).await;
-                let task = terminal_panel.update_in(&mut cx, |terminal_panel, window, cx| {
+            cx.spawn_in(window, async move |terminal_panel, cx| {
+                wait_for_terminals_tasks(terminals_for_task, cx).await;
+                let task = terminal_panel.update_in(cx, |terminal_panel, window, cx| {
                     if task.use_new_terminal {
                         terminal_panel
                             .spawn_in_new_terminal(task, window, cx)
@@ -669,14 +669,14 @@ impl TerminalPanel {
         }
         let window_handle = window.window_handle();
         let project = workspace.project().downgrade();
-        cx.spawn_in(window, move |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             let terminal = project
-                .update(&mut cx, |project, cx| {
+                .update(cx, |project, cx| {
                     project.create_terminal(kind, window_handle, cx)
                 })?
                 .await?;
 
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 let terminal_view = cx.new(|cx| {
                     TerminalView::new(
                         terminal.clone(),
@@ -701,24 +701,22 @@ impl TerminalPanel {
         cx: &mut Context<Self>,
     ) -> Task<Result<Entity<Terminal>>> {
         let workspace = self.workspace.clone();
-        cx.spawn_in(window, |terminal_panel, mut cx| async move {
-            if workspace.update(&mut cx, |workspace, cx| {
-                !is_enabled_in_workspace(workspace, cx)
-            })? {
+        cx.spawn_in(window, async move |terminal_panel, cx| {
+            if workspace.update(cx, |workspace, cx| !is_enabled_in_workspace(workspace, cx))? {
                 anyhow::bail!("terminal not yet supported for remote projects");
             }
-            let pane = terminal_panel.update(&mut cx, |terminal_panel, _| {
+            let pane = terminal_panel.update(cx, |terminal_panel, _| {
                 terminal_panel.pending_terminals_to_add += 1;
                 terminal_panel.active_pane.clone()
             })?;
-            let project = workspace.update(&mut cx, |workspace, _| workspace.project().clone())?;
+            let project = workspace.update(cx, |workspace, _| workspace.project().clone())?;
             let window_handle = cx.window_handle();
             let terminal = project
-                .update(&mut cx, |project, cx| {
+                .update(cx, |project, cx| {
                     project.create_terminal(kind, window_handle, cx)
                 })?
                 .await?;
-            let result = workspace.update_in(&mut cx, |workspace, window, cx| {
+            let result = workspace.update_in(cx, |workspace, window, cx| {
                 let terminal_view = Box::new(cx.new(|cx| {
                     TerminalView::new(
                         terminal.clone(),
@@ -748,7 +746,7 @@ impl TerminalPanel {
 
                 Ok(terminal)
             })?;
-            terminal_panel.update(&mut cx, |this, cx| {
+            terminal_panel.update(cx, |this, cx| {
                 this.pending_terminals_to_add = this.pending_terminals_to_add.saturating_sub(1);
                 this.serialize(cx)
             })?;
@@ -769,13 +767,13 @@ impl TerminalPanel {
         else {
             return;
         };
-        self.pending_serialization = cx.spawn(|terminal_panel, mut cx| async move {
+        self.pending_serialization = cx.spawn(async move |terminal_panel, cx| {
             cx.background_executor()
                 .timer(Duration::from_millis(50))
                 .await;
             let terminal_panel = terminal_panel.upgrade()?;
             let items = terminal_panel
-                .update(&mut cx, |terminal_panel, cx| {
+                .update(cx, |terminal_panel, cx| {
                     SerializedItems::WithSplits(serialize_pane_group(
                         &terminal_panel.center,
                         &terminal_panel.active_pane,
@@ -818,9 +816,9 @@ impl TerminalPanel {
         let reveal_target = spawn_task.reveal_target;
         let window_handle = window.window_handle();
         let task_workspace = self.workspace.clone();
-        cx.spawn_in(window, move |terminal_panel, mut cx| async move {
+        cx.spawn_in(window, async move |terminal_panel, cx| {
             let project = terminal_panel
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     this.workspace
                         .update(cx, |workspace, _| workspace.project().clone())
                         .ok()
@@ -828,14 +826,14 @@ impl TerminalPanel {
                 .ok()
                 .flatten()?;
             let new_terminal = project
-                .update(&mut cx, |project, cx| {
+                .update(cx, |project, cx| {
                     project.create_terminal(TerminalKind::Task(spawn_task), window_handle, cx)
                 })
                 .ok()?
                 .await
                 .log_err()?;
             terminal_to_replace
-                .update_in(&mut cx, |terminal_to_replace, window, cx| {
+                .update_in(cx, |terminal_to_replace, window, cx| {
                     terminal_to_replace.set_terminal(new_terminal, window, cx);
                 })
                 .ok()?;
@@ -844,7 +842,7 @@ impl TerminalPanel {
                 RevealStrategy::Always => match reveal_target {
                     RevealTarget::Center => {
                         task_workspace
-                            .update_in(&mut cx, |workspace, window, cx| {
+                            .update_in(cx, |workspace, window, cx| {
                                 workspace
                                     .active_item(cx)
                                     .context("retrieving active terminal item in the workspace")
@@ -857,7 +855,7 @@ impl TerminalPanel {
                     }
                     RevealTarget::Dock => {
                         terminal_panel
-                            .update_in(&mut cx, |terminal_panel, window, cx| {
+                            .update_in(cx, |terminal_panel, window, cx| {
                                 terminal_panel.activate_terminal_view(
                                     &task_pane,
                                     terminal_item_index,
@@ -868,9 +866,9 @@ impl TerminalPanel {
                             })
                             .ok()?;
 
-                        cx.spawn(|mut cx| async move {
+                        cx.spawn(async move |cx| {
                             task_workspace
-                                .update_in(&mut cx, |workspace, window, cx| {
+                                .update_in(cx, |workspace, window, cx| {
                                     workspace.focus_panel::<Self>(window, cx)
                                 })
                                 .ok()
@@ -881,14 +879,14 @@ impl TerminalPanel {
                 RevealStrategy::NoFocus => match reveal_target {
                     RevealTarget::Center => {
                         task_workspace
-                            .update_in(&mut cx, |workspace, window, cx| {
+                            .update_in(cx, |workspace, window, cx| {
                                 workspace.active_pane().focus_handle(cx).focus(window);
                             })
                             .ok()?;
                     }
                     RevealTarget::Dock => {
                         terminal_panel
-                            .update_in(&mut cx, |terminal_panel, window, cx| {
+                            .update_in(cx, |terminal_panel, window, cx| {
                                 terminal_panel.activate_terminal_view(
                                     &task_pane,
                                     terminal_item_index,
@@ -899,9 +897,9 @@ impl TerminalPanel {
                             })
                             .ok()?;
 
-                        cx.spawn(|mut cx| async move {
+                        cx.spawn(async move |cx| {
                             task_workspace
-                                .update_in(&mut cx, |workspace, window, cx| {
+                                .update_in(cx, |workspace, window, cx| {
                                     workspace.open_panel::<Self>(window, cx)
                                 })
                                 .ok()
@@ -1080,7 +1078,7 @@ pub fn new_terminal_pane(
                         match new_split_pane.transpose() {
                             // Source pane may be the one currently updated, so defer the move.
                             Ok(Some(new_pane)) => cx
-                                .spawn_in(window, |_, mut cx| async move {
+                                .spawn_in(window, async move |_, cx| {
                                     cx.update(|window, cx| {
                                         move_item(
                                             &source,

crates/terminal_view/src/terminal_view.rs 🔗

@@ -494,12 +494,10 @@ impl TerminalView {
             cx.notify();
 
             let epoch = self.next_blink_epoch();
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 Timer::after(CURSOR_BLINK_INTERVAL).await;
-                this.update_in(&mut cx, |this, window, cx| {
-                    this.blink_cursors(epoch, window, cx)
-                })
-                .ok();
+                this.update_in(cx, |this, window, cx| this.blink_cursors(epoch, window, cx))
+                    .ok();
             })
             .detach();
         }
@@ -510,9 +508,9 @@ impl TerminalView {
         cx.notify();
 
         let epoch = self.next_blink_epoch();
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             Timer::after(CURSOR_BLINK_INTERVAL).await;
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.resume_cursor_blinking(epoch, window, cx)
             })
             .ok();
@@ -727,12 +725,12 @@ impl TerminalView {
         if !Self::should_autohide_scrollbar(cx) {
             return;
         }
-        self.hide_scrollbar_task = Some(cx.spawn(|panel, mut cx| async move {
+        self.hide_scrollbar_task = Some(cx.spawn(async move |panel, cx| {
             cx.background_executor()
                 .timer(SCROLLBAR_SHOW_INTERVAL)
                 .await;
             panel
-                .update(&mut cx, |panel, cx| {
+                .update(cx, |panel, cx| {
                     panel.show_scrollbar = false;
                     cx.notify();
                 })
@@ -900,9 +898,9 @@ fn subscribe_for_terminal_events(
                     }
                     let task_workspace = workspace.clone();
                     let path_like_target = path_like_target.clone();
-                    cx.spawn_in(window, |terminal_view, mut cx| async move {
+                    cx.spawn_in(window, async move |terminal_view, cx| {
                         let open_target = terminal_view
-                            .update(&mut cx, |_, cx| {
+                            .update(cx, |_, cx| {
                                 possible_open_target(
                                     &task_workspace,
                                     &path_like_target.terminal_dir,
@@ -914,7 +912,7 @@ fn subscribe_for_terminal_events(
                         if let Some(open_target) = open_target {
                             let path_to_open = open_target.path();
                             let opened_items = task_workspace
-                                .update_in(&mut cx, |workspace, window, cx| {
+                                .update_in(cx, |workspace, window, cx| {
                                     workspace.open_paths(
                                         vec![path_to_open.path.clone()],
                                         OpenOptions {
@@ -945,7 +943,7 @@ fn subscribe_for_terminal_events(
                                             {
                                                 active_editor
                                                     .downgrade()
-                                                    .update_in(&mut cx, |editor, window, cx| {
+                                                    .update_in(cx, |editor, window, cx| {
                                                         editor.go_to_singleton_buffer_point(
                                                             language::Point::new(
                                                                 row.saturating_sub(1),
@@ -960,7 +958,7 @@ fn subscribe_for_terminal_events(
                                         }
                                     }
                                 } else if open_target.is_dir() {
-                                    task_workspace.update(&mut cx, |workspace, cx| {
+                                    task_workspace.update(cx, |workspace, cx| {
                                         workspace.project().update(cx, |_, cx| {
                                             cx.emit(project::Event::ActivateProjectPanel);
                                         })
@@ -1496,8 +1494,10 @@ impl SerializableItem for TerminalView {
         window: &mut Window,
         cx: &mut App,
     ) -> Task<gpui::Result<()>> {
-        window.spawn(cx, |_| {
-            TERMINAL_DB.delete_unloaded_items(workspace_id, alive_items)
+        window.spawn(cx, async move |_| {
+            TERMINAL_DB
+                .delete_unloaded_items(workspace_id, alive_items)
+                .await
         })
     }
 
@@ -1538,7 +1538,7 @@ impl SerializableItem for TerminalView {
         cx: &mut App,
     ) -> Task<anyhow::Result<Entity<Self>>> {
         let window_handle = window.window_handle();
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let cwd = cx
                 .update(|_window, cx| {
                     let from_db = TERMINAL_DB
@@ -1560,7 +1560,7 @@ impl SerializableItem for TerminalView {
                 .flatten();
 
             let terminal = project
-                .update(&mut cx, |project, cx| {
+                .update(cx, |project, cx| {
                     project.create_terminal(TerminalKind::Shell(cwd), window_handle, cx)
                 })?
                 .await?;

crates/theme_selector/src/icon_theme_selector.rs 🔗

@@ -218,7 +218,7 @@ impl PickerDelegate for IconThemeSelectorDelegate {
             .map(|(id, meta)| StringMatchCandidate::new(id, &meta.name))
             .collect::<Vec<_>>();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let matches = if query.is_empty() {
                 candidates
                     .into_iter()
@@ -242,7 +242,7 @@ impl PickerDelegate for IconThemeSelectorDelegate {
                 .await
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.delegate.matches = matches;
                 this.delegate.selected_index = this
                     .delegate

crates/theme_selector/src/theme_selector.rs 🔗

@@ -266,7 +266,7 @@ impl PickerDelegate for ThemeSelectorDelegate {
             .map(|(id, meta)| StringMatchCandidate::new(id, &meta.name))
             .collect::<Vec<_>>();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let matches = if query.is_empty() {
                 candidates
                     .into_iter()
@@ -290,7 +290,7 @@ impl PickerDelegate for ThemeSelectorDelegate {
                 .await
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.delegate.matches = matches;
                 this.delegate.selected_index = this
                     .delegate

crates/title_bar/src/title_bar.rs 🔗

@@ -642,11 +642,11 @@ impl TitleBar {
             .on_click(move |_, window, cx| {
                 let client = client.clone();
                 window
-                    .spawn(cx, move |mut cx| async move {
+                    .spawn(cx, async move |cx| {
                         client
                             .authenticate_and_connect(true, &cx)
                             .await
-                            .notify_async_err(&mut cx);
+                            .notify_async_err(cx);
                     })
                     .detach();
             })

crates/toolchain_selector/src/active_toolchain.rs 🔗

@@ -30,40 +30,38 @@ impl ActiveToolchain {
         }
     }
     fn spawn_tracker_task(window: &mut Window, cx: &mut Context<Self>) -> Task<Option<()>> {
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let active_file = this
-                .update(&mut cx, |this, _| {
+                .update(cx, |this, _| {
                     this.active_buffer
                         .as_ref()
                         .map(|(_, buffer, _)| buffer.clone())
                 })
                 .ok()
                 .flatten()?;
-            let workspace = this
-                .update(&mut cx, |this, _| this.workspace.clone())
-                .ok()?;
+            let workspace = this.update(cx, |this, _| this.workspace.clone()).ok()?;
             let language_name = active_file
-                .update(&mut cx, |this, _| Some(this.language()?.name()))
+                .update(cx, |this, _| Some(this.language()?.name()))
                 .ok()
                 .flatten()?;
             let term = workspace
-                .update(&mut cx, |workspace, cx| {
+                .update(cx, |workspace, cx| {
                     let languages = workspace.project().read(cx).languages();
                     Project::toolchain_term(languages.clone(), language_name.clone())
                 })
                 .ok()?
                 .await?;
-            let _ = this.update(&mut cx, |this, cx| {
+            let _ = this.update(cx, |this, cx| {
                 this.term = term;
                 cx.notify();
             });
             let worktree_id = active_file
-                .update(&mut cx, |this, cx| Some(this.file()?.worktree_id(cx)))
+                .update(cx, |this, cx| Some(this.file()?.worktree_id(cx)))
                 .ok()
                 .flatten()?;
             let toolchain =
-                Self::active_toolchain(workspace, worktree_id, language_name, &mut cx).await?;
-            let _ = this.update(&mut cx, |this, cx| {
+                Self::active_toolchain(workspace, worktree_id, language_name, cx).await?;
+            let _ = this.update(cx, |this, cx| {
                 this.active_toolchain = Some(toolchain);
 
                 cx.notify();
@@ -104,13 +102,13 @@ impl ActiveToolchain {
         language_name: LanguageName,
         cx: &mut AsyncWindowContext,
     ) -> Task<Option<Toolchain>> {
-        cx.spawn(move |mut cx| async move {
+        cx.spawn(async move |cx| {
             let workspace_id = workspace
-                .update(&mut cx, |this, _| this.database_id())
+                .update(cx, |this, _| this.database_id())
                 .ok()
                 .flatten()?;
             let selected_toolchain = workspace
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     this.project()
                         .read(cx)
                         .active_toolchain(worktree_id, language_name.clone(), cx)
@@ -121,7 +119,7 @@ impl ActiveToolchain {
                 Some(toolchain)
             } else {
                 let project = workspace
-                    .update(&mut cx, |this, _| this.project().clone())
+                    .update(cx, |this, _| this.project().clone())
                     .ok()?;
                 let toolchains = cx
                     .update(|_, cx| {
@@ -138,7 +136,7 @@ impl ActiveToolchain {
                         .await
                         .ok()?;
                     project
-                        .update(&mut cx, |this, cx| {
+                        .update(cx, |this, cx| {
                             this.activate_toolchain(worktree_id, toolchain.clone(), cx)
                         })
                         .ok()?

crates/toolchain_selector/src/toolchain_selector.rs 🔗

@@ -57,14 +57,14 @@ impl ToolchainSelector {
             .abs_path();
         let workspace_id = workspace.database_id()?;
         let weak = workspace.weak_handle();
-        cx.spawn_in(window, move |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             let active_toolchain = workspace::WORKSPACE_DB
                 .toolchain(workspace_id, worktree_id, language_name.clone())
                 .await
                 .ok()
                 .flatten();
             workspace
-                .update_in(&mut cx, |this, window, cx| {
+                .update_in(cx, |this, window, cx| {
                     this.toggle_modal(window, cx, move |window, cx| {
                         ToolchainSelector::new(
                             weak,
@@ -155,26 +155,26 @@ impl ToolchainSelectorDelegate {
     ) -> Self {
         let _fetch_candidates_task = cx.spawn_in(window, {
             let project = project.clone();
-            move |this, mut cx| async move {
+            async move |this, cx| {
                 let term = project
-                    .update(&mut cx, |this, _| {
+                    .update(cx, |this, _| {
                         Project::toolchain_term(this.languages().clone(), language_name.clone())
                     })
                     .ok()?
                     .await?;
                 let placeholder_text = format!("Select a {}…", term.to_lowercase()).into();
-                let _ = this.update_in(&mut cx, move |this, window, cx| {
+                let _ = this.update_in(cx, move |this, window, cx| {
                     this.delegate.placeholder_text = placeholder_text;
                     this.refresh_placeholder(window, cx);
                 });
                 let available_toolchains = project
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         this.available_toolchains(worktree_id, language_name, cx)
                     })
                     .ok()?
                     .await?;
 
-                let _ = this.update_in(&mut cx, move |this, window, cx| {
+                let _ = this.update_in(cx, move |this, window, cx| {
                     this.delegate.candidates = available_toolchains;
 
                     if let Some(active_toolchain) = active_toolchain {
@@ -239,13 +239,13 @@ impl PickerDelegate for ToolchainSelectorDelegate {
             {
                 let workspace = self.workspace.clone();
                 let worktree_id = self.worktree_id;
-                cx.spawn_in(window, |_, mut cx| async move {
+                cx.spawn_in(window, async move |_, cx| {
                     workspace::WORKSPACE_DB
                         .set_toolchain(workspace_id, worktree_id, toolchain.clone())
                         .await
                         .log_err();
                     workspace
-                        .update(&mut cx, |this, cx| {
+                        .update(cx, |this, cx| {
                             this.project().update(cx, |this, cx| {
                                 this.activate_toolchain(worktree_id, toolchain, cx)
                             })
@@ -288,7 +288,7 @@ impl PickerDelegate for ToolchainSelectorDelegate {
         let background = cx.background_executor().clone();
         let candidates = self.candidates.clone();
         let worktree_root_path = self.worktree_abs_path_root.clone();
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let matches = if query.is_empty() {
                 candidates
                     .toolchains
@@ -327,7 +327,7 @@ impl PickerDelegate for ToolchainSelectorDelegate {
                 .await
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 let delegate = &mut this.delegate;
                 delegate.matches = matches;
                 delegate.selected_index = delegate

crates/ui/src/components/context_menu.rs 🔗

@@ -557,7 +557,7 @@ impl ContextMenu {
             self.delayed = true;
             cx.notify();
             let action = dispatched.boxed_clone();
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 cx.background_executor()
                     .timer(Duration::from_millis(50))
                     .await;

crates/vim/src/command.rs 🔗

@@ -1192,7 +1192,7 @@ impl OnMatchingLines {
                 ..snapshot
                     .buffer_snapshot
                     .clip_point(Point::new(range.end.0 + 1, 0), Bias::Left);
-            cx.spawn_in(window, |editor, mut cx| async move {
+            cx.spawn_in(window, async move |editor, cx| {
                 let new_selections = cx
                     .background_spawn(async move {
                         let mut line = String::new();
@@ -1226,7 +1226,7 @@ impl OnMatchingLines {
                     return;
                 }
                 editor
-                    .update_in(&mut cx, |editor, window, cx| {
+                    .update_in(cx, |editor, window, cx| {
                         editor.start_transaction_at(Instant::now(), window, cx);
                         editor.change_selections(None, window, cx, |s| {
                             s.replace_cursors_with(|_| new_selections);
@@ -1511,9 +1511,9 @@ impl ShellExec {
         };
         let is_read = self.is_read;
 
-        let task = cx.spawn_in(window, |vim, mut cx| async move {
+        let task = cx.spawn_in(window, async move |vim, cx| {
             let Some(mut running) = process.spawn().log_err() else {
-                vim.update_in(&mut cx, |vim, window, cx| {
+                vim.update_in(cx, |vim, window, cx| {
                     vim.cancel_running_command(window, cx);
                 })
                 .log_err();
@@ -1540,7 +1540,7 @@ impl ShellExec {
                 .await;
 
             let Some(output) = output.log_err() else {
-                vim.update_in(&mut cx, |vim, window, cx| {
+                vim.update_in(cx, |vim, window, cx| {
                     vim.cancel_running_command(window, cx);
                 })
                 .log_err();
@@ -1556,7 +1556,7 @@ impl ShellExec {
                 text.push('\n');
             }
 
-            vim.update_in(&mut cx, |vim, window, cx| {
+            vim.update_in(cx, |vim, window, cx| {
                 vim.update_editor(window, cx, |_, editor, window, cx| {
                     editor.transact(window, cx, |editor, window, cx| {
                         editor.edit([(range.clone(), text)], cx);

crates/vim/src/normal/mark.rs 🔗

@@ -147,9 +147,9 @@ impl Vim {
                 cx,
             )
         });
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let editor = task.await?;
-            this.update_in(&mut cx, |_, window, cx| {
+            this.update_in(cx, |_, window, cx| {
                 if let Some(editor) = editor.act_as::<Editor>(cx) {
                     editor.update(cx, |editor, cx| {
                         let map = editor.snapshot(window, cx);

crates/vim/src/normal/search.rs 🔗

@@ -341,9 +341,9 @@ impl Vim {
             let Some(search) = search else { return false };
 
             let search_bar = search_bar.downgrade();
-            cx.spawn_in(window, |_, mut cx| async move {
+            cx.spawn_in(window, async move |_, cx| {
                 search.await?;
-                search_bar.update_in(&mut cx, |search_bar, window, cx| {
+                search_bar.update_in(cx, |search_bar, window, cx| {
                     search_bar.select_match(direction, count, window, cx);
 
                     vim.update(cx, |vim, cx| {
@@ -404,9 +404,9 @@ impl Vim {
                 } else {
                     Direction::Next
                 };
-                cx.spawn_in(window, |_, mut cx| async move {
+                cx.spawn_in(window, async move |_, cx| {
                     search.await?;
-                    search_bar.update_in(&mut cx, |search_bar, window, cx| {
+                    search_bar.update_in(cx, |search_bar, window, cx| {
                         search_bar.select_match(direction, 1, window, cx)
                     })?;
                     anyhow::Ok(())
@@ -473,18 +473,18 @@ impl Vim {
             });
             let Some(search) = search else { return };
             let search_bar = search_bar.downgrade();
-            cx.spawn_in(window, |_, mut cx| async move {
+            cx.spawn_in(window, async move |_, cx| {
                 search.await?;
-                search_bar.update_in(&mut cx, |search_bar, window, cx| {
+                search_bar.update_in(cx, |search_bar, window, cx| {
                     if replacement.should_replace_all {
                         search_bar.select_last_match(window, cx);
                         search_bar.replace_all(&Default::default(), window, cx);
-                        cx.spawn(|_, mut cx| async move {
+                        cx.spawn(async move |_, cx| {
                             cx.background_executor()
                                 .timer(Duration::from_millis(200))
                                 .await;
                             editor
-                                .update(&mut cx, |editor, cx| editor.clear_search_within_ranges(cx))
+                                .update(cx, |editor, cx| editor.clear_search_within_ranges(cx))
                                 .ok();
                         })
                         .detach();

crates/vim/src/normal/yank.rs 🔗

@@ -228,11 +228,11 @@ impl Vim {
             |colors| colors.editor_document_highlight_read_background,
             cx,
         );
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             cx.background_executor()
                 .timer(Duration::from_millis(highlight_duration))
                 .await;
-            this.update(&mut cx, |editor, cx| {
+            this.update(cx, |editor, cx| {
                 editor.clear_background_highlights::<HighlightOnYank>(cx)
             })
             .ok();

crates/vim/src/state.rs 🔗

@@ -288,8 +288,8 @@ impl MarksState {
     }
 
     fn load(&mut self, cx: &mut Context<Self>) {
-        cx.spawn(|this, mut cx| async move {
-            let Some(workspace_id) = this.update(&mut cx, |this, cx| this.workspace_id(cx))? else {
+        cx.spawn(async move |this, cx| {
+            let Some(workspace_id) = this.update(cx, |this, cx| this.workspace_id(cx))? else {
                 return Ok(());
             };
             let (marks, paths) = cx
@@ -299,7 +299,7 @@ impl MarksState {
                     anyhow::Ok((marks, paths))
                 })
                 .await?;
-            this.update(&mut cx, |this, cx| this.loaded(marks, paths, cx))
+            this.update(cx, |this, cx| this.loaded(marks, paths, cx))
         })
         .detach_and_log_err(cx);
     }

crates/welcome/src/base_keymap_picker.rs 🔗

@@ -130,7 +130,7 @@ impl PickerDelegate for BaseKeymapSelectorDelegate {
             .map(|(id, name)| StringMatchCandidate::new(id, name))
             .collect::<Vec<_>>();
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let matches = if query.is_empty() {
                 candidates
                     .into_iter()
@@ -154,7 +154,7 @@ impl PickerDelegate for BaseKeymapSelectorDelegate {
                 .await
             };
 
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 this.delegate.matches = matches;
                 this.delegate.selected_index = this
                     .delegate

crates/welcome/src/welcome.rs 🔗

@@ -221,7 +221,7 @@ impl Render for WelcomePage {
                                                 .on_click(cx.listener(|_, _, _, cx| {
                                                     telemetry::event!("Welcome CLI Installed");
                                                     cx
-                                                        .spawn(|_, cx| async move {
+                                                        .spawn(async move |_, cx| {
                                                             install_cli::install_cli(&cx).await
                                                         })
                                                         .detach_and_log_err(cx);

crates/workspace/src/item.rs 🔗

@@ -718,13 +718,13 @@ impl<T: Item> ItemHandle for Entity<T> {
 
                 send_follower_updates = Some(cx.spawn_in(window, {
                     let pending_update = pending_update.clone();
-                    |workspace, mut cx| async move {
+                    async move |workspace, cx| {
                         while let Some(mut leader_id) = pending_update_rx.next().await {
                             while let Ok(Some(id)) = pending_update_rx.try_next() {
                                 leader_id = id;
                             }
 
-                            workspace.update_in(&mut cx, |workspace, window, cx| {
+                            workspace.update_in(cx, |workspace, window, cx| {
                                 let Some(item) = item.upgrade() else { return };
                                 workspace.update_followers(
                                     is_project_item,

crates/workspace/src/notifications.rs 🔗

@@ -151,14 +151,12 @@ impl Workspace {
             })
         });
         if toast.autohide {
-            cx.spawn(|workspace, mut cx| async move {
+            cx.spawn(async move |workspace, cx| {
                 cx.background_executor()
                     .timer(Duration::from_millis(5000))
                     .await;
                 workspace
-                    .update(&mut cx, |workspace, cx| {
-                        workspace.dismiss_toast(&toast.id, cx)
-                    })
+                    .update(cx, |workspace, cx| workspace.dismiss_toast(&toast.id, cx))
                     .ok();
             })
             .detach();
@@ -213,9 +211,9 @@ impl LanguageServerPrompt {
         }
     }
 
-    async fn select_option(this: Entity<Self>, ix: usize, mut cx: AsyncWindowContext) {
+    async fn select_option(this: Entity<Self>, ix: usize, cx: &mut AsyncWindowContext) {
         util::maybe!(async move {
-            let potential_future = this.update(&mut cx, |this, _| {
+            let potential_future = this.update(cx, |this, _| {
                 this.request.take().map(|request| request.respond(ix))
             });
 
@@ -224,7 +222,7 @@ impl LanguageServerPrompt {
                 .await
                 .ok_or_else(|| anyhow::anyhow!("Stream already closed"))?;
 
-            this.update(&mut cx, |_, cx| cx.emit(DismissEvent))?;
+            this.update(cx, |_, cx| cx.emit(DismissEvent))?;
 
             anyhow::Ok(())
         })
@@ -295,7 +293,7 @@ impl Render for LanguageServerPrompt {
                             .on_click(move |_, window, cx| {
                                 let this_handle = this_handle.clone();
                                 window
-                                    .spawn(cx, |cx| async move {
+                                    .spawn(cx, async move |cx| {
                                         LanguageServerPrompt::select_option(this_handle, ix, cx)
                                             .await
                                     })
@@ -846,10 +844,7 @@ where
 {
     fn detach_and_notify_err(self, window: &mut Window, cx: &mut App) {
         window
-            .spawn(
-                cx,
-                |mut cx| async move { self.await.notify_async_err(&mut cx) },
-            )
+            .spawn(cx, async move |mut cx| self.await.notify_async_err(&mut cx))
             .detach();
     }
 }
@@ -884,7 +879,7 @@ where
         f: impl FnOnce(&anyhow::Error, &mut Window, &mut App) -> Option<String> + 'static,
     ) -> Task<Option<R>> {
         let msg = msg.to_owned();
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let result = self.await;
             if let Err(err) = result.as_ref() {
                 log::error!("{err:?}");

crates/workspace/src/pane.rs 🔗

@@ -1582,8 +1582,8 @@ impl Pane {
         let Some(project) = self.project.upgrade() else {
             return Task::ready(Ok(()));
         };
-        cx.spawn_in(window, |pane, mut cx| async move {
-            let dirty_items = workspace.update(&mut cx, |workspace, cx| {
+        cx.spawn_in(window, async move |pane, cx| {
+            let dirty_items = workspace.update(cx, |workspace, cx| {
                 items_to_close
                     .iter()
                     .filter(|item| {
@@ -1595,7 +1595,7 @@ impl Pane {
             })?;
 
             if save_intent == SaveIntent::Close && dirty_items.len() > 1 {
-                let answer = pane.update_in(&mut cx, |_, window, cx| {
+                let answer = pane.update_in(cx, |_, window, cx| {
                     let detail = Self::file_names_for_prompt(&mut dirty_items.iter(), cx);
                     window.prompt(
                         PromptLevel::Warning,
@@ -1616,7 +1616,7 @@ impl Pane {
             for item_to_close in items_to_close {
                 let mut should_save = true;
                 if save_intent == SaveIntent::Close {
-                    workspace.update(&mut cx, |workspace, cx| {
+                    workspace.update(cx, |workspace, cx| {
                         if Self::skip_save_on_close(item_to_close.as_ref(), &workspace, cx) {
                             should_save = false;
                         }
@@ -1624,21 +1624,15 @@ impl Pane {
                 }
 
                 if should_save {
-                    if !Self::save_item(
-                        project.clone(),
-                        &pane,
-                        &*item_to_close,
-                        save_intent,
-                        &mut cx,
-                    )
-                    .await?
+                    if !Self::save_item(project.clone(), &pane, &*item_to_close, save_intent, cx)
+                        .await?
                     {
                         break;
                     }
                 }
 
                 // Remove the item from the pane.
-                pane.update_in(&mut cx, |pane, window, cx| {
+                pane.update_in(cx, |pane, window, cx| {
                     pane.remove_item(
                         item_to_close.item_id(),
                         false,
@@ -1651,7 +1645,7 @@ impl Pane {
                 .ok();
             }
 
-            pane.update(&mut cx, |_, cx| cx.notify()).ok();
+            pane.update(cx, |_, cx| cx.notify()).ok();
             Ok(())
         })
     }
@@ -2980,12 +2974,12 @@ impl Pane {
                         .path_for_entry(project_entry_id, cx)
                     {
                         let load_path_task = workspace.load_path(path, window, cx);
-                        cx.spawn_in(window, |workspace, mut cx| async move {
+                        cx.spawn_in(window, async move |workspace, cx| {
                             if let Some((project_entry_id, build_item)) =
-                                load_path_task.await.notify_async_err(&mut cx)
+                                load_path_task.await.notify_async_err(cx)
                             {
                                 let (to_pane, new_item_handle) = workspace
-                                    .update_in(&mut cx, |workspace, window, cx| {
+                                    .update_in(cx, |workspace, window, cx| {
                                         if let Some(split_direction) = split_direction {
                                             to_pane = workspace.split_pane(
                                                 to_pane,
@@ -3010,7 +3004,7 @@ impl Pane {
                                     })
                                     .log_err()?;
                                 to_pane
-                                    .update_in(&mut cx, |this, window, cx| {
+                                    .update_in(cx, |this, window, cx| {
                                         let Some(index) = this.index_for_item(&*new_item_handle)
                                         else {
                                             return;
@@ -3067,7 +3061,7 @@ impl Pane {
         self.workspace
             .update(cx, |workspace, cx| {
                 let fs = Arc::clone(workspace.project().read(cx).fs());
-                cx.spawn_in(window, |workspace, mut cx| async move {
+                cx.spawn_in(window, async move |workspace, cx| {
                     let mut is_file_checks = FuturesUnordered::new();
                     for path in &paths {
                         is_file_checks.push(fs.is_file(path))
@@ -3084,7 +3078,7 @@ impl Pane {
                         split_direction = None;
                     }
 
-                    if let Ok(open_task) = workspace.update_in(&mut cx, |workspace, window, cx| {
+                    if let Ok(open_task) = workspace.update_in(cx, |workspace, window, cx| {
                         if let Some(split_direction) = split_direction {
                             to_pane = workspace.split_pane(to_pane, split_direction, window, cx);
                         }
@@ -3100,7 +3094,7 @@ impl Pane {
                         )
                     }) {
                         let opened_items: Vec<_> = open_task.await;
-                        _ = workspace.update(&mut cx, |workspace, cx| {
+                        _ = workspace.update(cx, |workspace, cx| {
                             for item in opened_items.into_iter().flatten() {
                                 if let Err(e) = item {
                                     workspace.show_error(&e, cx);

crates/workspace/src/searchable.rs 🔗

@@ -303,7 +303,7 @@ impl<T: SearchableItem> SearchableItemHandle for Entity<T> {
         cx: &mut App,
     ) -> Task<AnyVec<dyn Send>> {
         let matches = self.update(cx, |this, cx| this.find_matches(query, window, cx));
-        window.spawn(cx, |_| async {
+        window.spawn(cx, async |_| {
             let matches = matches.await;
             let mut any_matches = AnyVec::with_capacity::<T::Match>(matches.len());
             {

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

@@ -43,14 +43,14 @@ impl SharedScreen {
             peer_id,
             user,
             nav_history: Default::default(),
-            _maintain_frame: cx.spawn_in(window, |this, mut cx| async move {
+            _maintain_frame: cx.spawn_in(window, async move |this, cx| {
                 while let Some(frame) = frames.next().await {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.frame = Some(frame);
                         cx.notify();
                     })?;
                 }
-                this.update(&mut cx, |_, cx| cx.emit(Event::Close))?;
+                this.update(cx, |_, cx| cx.emit(Event::Close))?;
                 Ok(())
             }),
             focus: cx.focus_handle(),

crates/workspace/src/toast_layer.rs 🔗

@@ -182,11 +182,11 @@ impl ToastLayer {
         self.clear_dismiss_timer(cx);
 
         let instant_started = std::time::Instant::now();
-        let task = cx.spawn(|this, mut cx| async move {
+        let task = cx.spawn(async move |this, cx| {
             cx.background_executor().timer(duration).await;
 
             if let Some(this) = this.upgrade() {
-                this.update(&mut cx, |this, cx| this.hide_toast(cx)).ok();
+                this.update(cx, |this, cx| this.hide_toast(cx)).ok();
             }
         });
 

crates/workspace/src/workspace.rs 🔗

@@ -368,8 +368,8 @@ pub fn init_settings(cx: &mut App) {
 
 fn prompt_and_open_paths(app_state: Arc<AppState>, options: PathPromptOptions, cx: &mut App) {
     let paths = cx.prompt_for_paths(options);
-    cx.spawn(|cx| async move {
-        match paths.await.anyhow().and_then(|res| res) {
+    cx.spawn(
+        async move |cx| match paths.await.anyhow().and_then(|res| res) {
             Ok(Some(paths)) => {
                 cx.update(|cx| {
                     open_paths(&paths, app_state, OpenOptions::default(), cx).detach_and_log_err(cx)
@@ -393,8 +393,8 @@ fn prompt_and_open_paths(app_state: Arc<AppState>, options: PathPromptOptions, c
                 })
                 .ok();
             }
-        }
-    })
+        },
+    )
     .detach();
 }
 
@@ -465,10 +465,10 @@ pub fn register_project_item<I: ProjectItem>(cx: &mut App) {
     builders.push(|project, project_path, window, cx| {
         let project_item = <I::Item as project::ProjectItem>::try_open(project, project_path, cx)?;
         let project = project.clone();
-        Some(window.spawn(cx, |cx| async move {
+        Some(window.spawn(cx, async move |cx| {
             let project_item = project_item.await?;
             let project_entry_id: Option<ProjectEntryId> =
-                project_item.read_with(&cx, project::ProjectItem::entry_id)?;
+                project_item.read_with(cx, project::ProjectItem::entry_id)?;
             let build_workspace_item = Box::new(|window: &mut Window, cx: &mut Context<Pane>| {
                 Box::new(cx.new(|cx| I::for_project_item(project, project_item, window, cx)))
                     as Box<dyn ItemHandle>
@@ -741,7 +741,7 @@ impl DelayedDebouncedEditAction {
         self.cancel_channel = Some(sender);
 
         let previous_task = self.task.take();
-        self.task = Some(cx.spawn_in(window, move |workspace, mut cx| async move {
+        self.task = Some(cx.spawn_in(window, async move |workspace, cx| {
             let mut timer = cx.background_executor().timer(delay).fuse();
             if let Some(previous_task) = previous_task {
                 previous_task.await;
@@ -753,9 +753,7 @@ impl DelayedDebouncedEditAction {
             }
 
             if let Some(result) = workspace
-                .update_in(&mut cx, |workspace, window, cx| {
-                    (func)(workspace, window, cx)
-                })
+                .update_in(cx, |workspace, window, cx| (func)(workspace, window, cx))
                 .log_err()
             {
                 result.await.log_err();
@@ -1011,14 +1009,14 @@ impl Workspace {
 
         let mut current_user = app_state.user_store.read(cx).watch_current_user();
         let mut connection_status = app_state.client.status();
-        let _observe_current_user = cx.spawn_in(window, |this, mut cx| async move {
+        let _observe_current_user = cx.spawn_in(window, async move |this, cx| {
             current_user.next().await;
             connection_status.next().await;
             let mut stream =
                 Stream::map(current_user, drop).merge(Stream::map(connection_status, drop));
 
             while stream.recv().await.is_some() {
-                this.update(&mut cx, |_, cx| cx.notify())?;
+                this.update(cx, |_, cx| cx.notify())?;
             }
             anyhow::Ok(())
         });
@@ -1027,9 +1025,9 @@ impl Workspace {
         // that each asynchronous operation can be run in order.
         let (leader_updates_tx, mut leader_updates_rx) =
             mpsc::unbounded::<(PeerId, proto::UpdateFollowers)>();
-        let _apply_leader_updates = cx.spawn_in(window, |this, mut cx| async move {
+        let _apply_leader_updates = cx.spawn_in(window, async move |this, cx| {
             while let Some((leader_id, update)) = leader_updates_rx.next().await {
-                Self::process_leader_update(&this, leader_id, update, &mut cx)
+                Self::process_leader_update(&this, leader_id, update, cx)
                     .await
                     .log_err();
             }
@@ -1066,8 +1064,8 @@ impl Workspace {
 
         let (serializable_items_tx, serializable_items_rx) =
             mpsc::unbounded::<Box<dyn SerializableItemHandle>>();
-        let _items_serializer = cx.spawn_in(window, |this, mut cx| async move {
-            Self::serialize_items(&this, serializable_items_rx, &mut cx).await
+        let _items_serializer = cx.spawn_in(window, async move |this, cx| {
+            Self::serialize_items(&this, serializable_items_rx, cx).await
         });
 
         let subscriptions = vec![
@@ -1076,30 +1074,29 @@ impl Workspace {
                 if this.bounds_save_task_queued.is_some() {
                     return;
                 }
-                this.bounds_save_task_queued =
-                    Some(cx.spawn_in(window, |this, mut cx| async move {
-                        cx.background_executor()
-                            .timer(Duration::from_millis(100))
-                            .await;
-                        this.update_in(&mut cx, |this, window, cx| {
-                            if let Some(display) = window.display(cx) {
-                                if let Ok(display_uuid) = display.uuid() {
-                                    let window_bounds = window.inner_window_bounds();
-                                    if let Some(database_id) = workspace_id {
-                                        cx.background_executor()
-                                            .spawn(DB.set_window_open_status(
-                                                database_id,
-                                                SerializedWindowBounds(window_bounds),
-                                                display_uuid,
-                                            ))
-                                            .detach_and_log_err(cx);
-                                    }
+                this.bounds_save_task_queued = Some(cx.spawn_in(window, async move |this, cx| {
+                    cx.background_executor()
+                        .timer(Duration::from_millis(100))
+                        .await;
+                    this.update_in(cx, |this, window, cx| {
+                        if let Some(display) = window.display(cx) {
+                            if let Ok(display_uuid) = display.uuid() {
+                                let window_bounds = window.inner_window_bounds();
+                                if let Some(database_id) = workspace_id {
+                                    cx.background_executor()
+                                        .spawn(DB.set_window_open_status(
+                                            database_id,
+                                            SerializedWindowBounds(window_bounds),
+                                            display_uuid,
+                                        ))
+                                        .detach_and_log_err(cx);
                                 }
                             }
-                            this.bounds_save_task_queued.take();
-                        })
-                        .ok();
-                    }));
+                        }
+                        this.bounds_save_task_queued.take();
+                    })
+                    .ok();
+                }));
                 cx.notify();
             }),
             cx.observe_window_appearance(window, |_, window, cx| {
@@ -1191,7 +1188,7 @@ impl Workspace {
             cx,
         );
 
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let mut paths_to_open = Vec::with_capacity(abs_paths.len());
             for path in abs_paths.into_iter() {
                 if let Some(canonical) = app_state.fs.canonicalize(&path).await.ok() {
@@ -1219,7 +1216,7 @@ impl Workspace {
 
                 if order.iter().enumerate().any(|(i, &j)| i != j) {
                     project_handle
-                        .update(&mut cx, |project, cx| {
+                        .update(cx, |project, cx| {
                             project.set_worktrees_reordered(true, cx);
                         })
                         .log_err();
@@ -1253,7 +1250,7 @@ impl Workspace {
             let toolchains = DB.toolchains(workspace_id).await?;
             for (toolchain, worktree_id) in toolchains {
                 project_handle
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         this.activate_toolchain(worktree_id, toolchain, cx)
                     })?
                     .await;
@@ -1318,16 +1315,16 @@ impl Workspace {
                 })?
             };
 
-            notify_if_database_failed(window, &mut cx);
+            notify_if_database_failed(window, cx);
             let opened_items = window
-                .update(&mut cx, |_workspace, window, cx| {
+                .update(cx, |_workspace, window, cx| {
                     open_items(serialized_workspace, project_paths, window, cx)
                 })?
                 .await
                 .unwrap_or_default();
 
             window
-                .update(&mut cx, |_, window, _| window.activate_window())
+                .update(cx, |_, window, _| window.activate_window())
                 .log_err();
             Ok((window, opened_items))
         })
@@ -1513,19 +1510,19 @@ impl Workspace {
             // If the item was no longer present, then load it again from its previous path, first try the local path
             let open_by_project_path = self.load_path(project_path.clone(), window, cx);
 
-            cx.spawn_in(window, |workspace, mut cx| async move {
+            cx.spawn_in(window, async move  |workspace, cx| {
                 let open_by_project_path = open_by_project_path.await;
                 let mut navigated = false;
                 match open_by_project_path
                     .with_context(|| format!("Navigating to {project_path:?}"))
                 {
                     Ok((project_entry_id, build_item)) => {
-                        let prev_active_item_id = pane.update(&mut cx, |pane, _| {
+                        let prev_active_item_id = pane.update(cx, |pane, _| {
                             pane.nav_history_mut().set_mode(mode);
                             pane.active_item().map(|p| p.item_id())
                         })?;
 
-                        pane.update_in(&mut cx, |pane, window, cx| {
+                        pane.update_in(cx, |pane, window, cx| {
                             let item = pane.open_item(
                                 project_entry_id,
                                 true,
@@ -1546,11 +1543,11 @@ impl Workspace {
                         // Fall back to opening by abs path, in case an external file was opened and closed,
                         // and its worktree is now dropped
                         if let Some(abs_path) = abs_path {
-                            let prev_active_item_id = pane.update(&mut cx, |pane, _| {
+                            let prev_active_item_id = pane.update(cx, |pane, _| {
                                 pane.nav_history_mut().set_mode(mode);
                                 pane.active_item().map(|p| p.item_id())
                             })?;
-                            let open_by_abs_path = workspace.update_in(&mut cx, |workspace, window, cx| {
+                            let open_by_abs_path = workspace.update_in(cx, |workspace, window, cx| {
                                 workspace.open_abs_path(abs_path.clone(), OpenOptions { visible: Some(OpenVisible::None), ..Default::default() }, window, cx)
                             })?;
                             match open_by_abs_path
@@ -1558,7 +1555,7 @@ impl Workspace {
                                 .with_context(|| format!("Navigating to {abs_path:?}"))
                             {
                                 Ok(item) => {
-                                    pane.update_in(&mut cx, |pane, window, cx| {
+                                    pane.update_in(cx, |pane, window, cx| {
                                         navigated |= Some(item.item_id()) != prev_active_item_id;
                                         pane.nav_history_mut().set_mode(NavigationMode::Normal);
                                         if let Some(data) = entry.data {
@@ -1576,7 +1573,7 @@ impl Workspace {
 
                 if !navigated {
                     workspace
-                        .update_in(&mut cx, |workspace, window, cx| {
+                        .update_in(cx, |workspace, window, cx| {
                             Self::navigate_history(workspace, pane, mode, window, cx)
                         })?
                         .await?;
@@ -1661,7 +1658,7 @@ impl Workspace {
             let (tx, rx) = oneshot::channel();
             let abs_path = cx.prompt_for_paths(path_prompt_options);
 
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 let Ok(result) = abs_path.await else {
                     return Ok(());
                 };
@@ -1671,7 +1668,7 @@ impl Workspace {
                         tx.send(result).log_err();
                     }
                     Err(err) => {
-                        let rx = this.update_in(&mut cx, |this, window, cx| {
+                        let rx = this.update_in(cx, |this, window, cx| {
                             this.show_portal_error(err.to_string(), cx);
                             let prompt = this.on_prompt_for_open_path.take().unwrap();
                             let rx = prompt(this, lister, window, cx);
@@ -1714,11 +1711,11 @@ impl Workspace {
 
             let (tx, rx) = oneshot::channel();
             let abs_path = cx.prompt_for_new_path(&start_abs_path);
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 let abs_path = match abs_path.await? {
                     Ok(path) => path,
                     Err(err) => {
-                        let rx = this.update_in(&mut cx, |this, window, cx| {
+                        let rx = this.update_in(cx, |this, window, cx| {
                             this.show_portal_error(err.to_string(), cx);
 
                             let prompt = this.on_prompt_for_new_path.take().unwrap();
@@ -1734,7 +1731,7 @@ impl Workspace {
                 };
 
                 let project_path = abs_path.and_then(|abs_path| {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         this.project.update(cx, |project, cx| {
                             project.find_or_create_worktree(abs_path, true, cx)
                         })
@@ -1744,7 +1741,7 @@ impl Workspace {
 
                 if let Some(project_path) = project_path {
                     let (worktree, path) = project_path.await?;
-                    let worktree_id = worktree.read_with(&cx, |worktree, _| worktree.id())?;
+                    let worktree_id = worktree.read_with(cx, |worktree, _| worktree.id())?;
                     tx.send(Some(ProjectPath {
                         worktree_id,
                         path: path.into(),
@@ -1784,9 +1781,9 @@ impl Workspace {
         } else {
             let env = self.project.read(cx).cli_environment(cx);
             let task = Self::new_local(Vec::new(), self.app_state.clone(), None, env, cx);
-            cx.spawn_in(window, |_vh, mut cx| async move {
+            cx.spawn_in(window, async move |_vh, cx| {
                 let (workspace, _) = task.await?;
-                workspace.update(&mut cx, callback)
+                workspace.update(cx, callback)
             })
         }
     }
@@ -1837,7 +1834,7 @@ impl Workspace {
 
     pub fn close_window(&mut self, _: &CloseWindow, window: &mut Window, cx: &mut Context<Self>) {
         let prepare = self.prepare_to_close(CloseIntent::CloseWindow, window, cx);
-        cx.spawn_in(window, |_, mut cx| async move {
+        cx.spawn_in(window, async move |_, cx| {
             if prepare.await? {
                 cx.update(|window, _cx| window.remove_window())?;
             }
@@ -1883,7 +1880,7 @@ impl Workspace {
             && close_intent != CloseIntent::ReplaceWindow
             && cx.windows().len() == 1;
 
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let workspace_count = cx.update(|_window, cx| {
                 cx.windows()
                     .iter()
@@ -1894,7 +1891,7 @@ impl Workspace {
             if let Some(active_call) = active_call {
                 if close_intent != CloseIntent::Quit
                     && workspace_count == 1
-                    && active_call.read_with(&cx, |call, _| call.room().is_some())?
+                    && active_call.read_with(cx, |call, _| call.room().is_some())?
                 {
                     let answer = cx.update(|window, cx| {
                         window.prompt(
@@ -1910,7 +1907,7 @@ impl Workspace {
                         return anyhow::Ok(false);
                     } else {
                         active_call
-                            .update(&mut cx, |call, cx| call.hang_up(cx))?
+                            .update(cx, |call, cx| call.hang_up(cx))?
                             .await
                             .log_err();
                     }
@@ -1918,7 +1915,7 @@ impl Workspace {
             }
 
             let save_result = this
-                .update_in(&mut cx, |this, window, cx| {
+                .update_in(cx, |this, window, cx| {
                     this.save_all_internal(SaveIntent::Close, window, cx)
                 })?
                 .await;
@@ -1929,10 +1926,8 @@ impl Workspace {
                 && !save_last_workspace
                 && save_result.as_ref().map_or(false, |&res| res)
             {
-                this.update_in(&mut cx, |this, window, cx| {
-                    this.remove_from_session(window, cx)
-                })?
-                .await;
+                this.update_in(cx, |this, window, cx| this.remove_from_session(window, cx))?
+                    .await;
             }
 
             save_result
@@ -1971,7 +1966,7 @@ impl Workspace {
 
         let keystrokes = self.dispatching_keystrokes.clone();
         window
-            .spawn(cx, |mut cx| async move {
+            .spawn(cx, async move |cx| {
                 // limit to 100 keystrokes to avoid infinite recursion.
                 for _ in 0..100 {
                     let Some(keystroke) = keystrokes.borrow_mut().1.pop() else {
@@ -2024,10 +2019,10 @@ impl Workspace {
             .collect::<Vec<_>>();
 
         let project = self.project.clone();
-        cx.spawn_in(window, |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             let dirty_items = if save_intent == SaveIntent::Close && !dirty_items.is_empty() {
                 let (serialize_tasks, remaining_dirty_items) =
-                    workspace.update_in(&mut cx, |workspace, window, cx| {
+                    workspace.update_in(cx, |workspace, window, cx| {
                         let mut remaining_dirty_items = Vec::new();
                         let mut serialize_tasks = Vec::new();
                         for (pane, item) in dirty_items {
@@ -2046,7 +2041,7 @@ impl Workspace {
                 futures::future::try_join_all(serialize_tasks).await?;
 
                 if remaining_dirty_items.len() > 1 {
-                    let answer = workspace.update_in(&mut cx, |_, window, cx| {
+                    let answer = workspace.update_in(cx, |_, window, cx| {
                         let detail = Pane::file_names_for_prompt(
                             &mut remaining_dirty_items.iter().map(|(_, handle)| handle),
                             cx,
@@ -2076,9 +2071,7 @@ impl Workspace {
                 let (singleton, project_entry_ids) =
                     cx.update(|_, cx| (item.is_singleton(cx), item.project_entry_ids(cx)))?;
                 if singleton || !project_entry_ids.is_empty() {
-                    if !Pane::save_item(project.clone(), &pane, &*item, save_intent, &mut cx)
-                        .await?
-                    {
+                    if !Pane::save_item(project.clone(), &pane, &*item, save_intent, cx).await? {
                         return Ok(false);
                     }
                 }
@@ -2108,7 +2101,7 @@ impl Workspace {
         };
         let app_state = self.app_state.clone();
 
-        cx.spawn(|_, cx| async move {
+        cx.spawn(async move |_, cx| {
             cx.update(|cx| {
                 open_paths(
                     &paths,
@@ -2140,7 +2133,7 @@ impl Workspace {
 
         // Sort the paths to ensure we add worktrees for parents before their children.
         abs_paths.sort_unstable();
-        cx.spawn_in(window, move |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let mut tasks = Vec::with_capacity(abs_paths.len());
 
             for abs_path in &abs_paths {
@@ -2160,7 +2153,7 @@ impl Workspace {
                 };
                 let project_path = match visible {
                     Some(visible) => match this
-                        .update(&mut cx, |this, cx| {
+                        .update(cx, |this, cx| {
                             Workspace::project_path_for_path(
                                 this.project.clone(),
                                 abs_path,
@@ -2180,10 +2173,10 @@ impl Workspace {
                 let abs_path: Arc<Path> = SanitizedPath::from(abs_path.clone()).into();
                 let fs = fs.clone();
                 let pane = pane.clone();
-                let task = cx.spawn(move |mut cx| async move {
+                let task = cx.spawn(async move |cx| {
                     let (worktree, project_path) = project_path?;
                     if fs.is_dir(&abs_path).await {
-                        this.update(&mut cx, |workspace, cx| {
+                        this.update(cx, |workspace, cx| {
                             let worktree = worktree.read(cx);
                             let worktree_abs_path = worktree.abs_path();
                             let entry_id = if abs_path.as_ref() == worktree_abs_path.as_ref() {
@@ -2207,7 +2200,7 @@ impl Workspace {
                         None
                     } else {
                         Some(
-                            this.update_in(&mut cx, |this, window, cx| {
+                            this.update_in(cx, |this, window, cx| {
                                 this.open_path(
                                     project_path,
                                     pane,
@@ -2286,10 +2279,10 @@ impl Workspace {
             window,
             cx,
         );
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             if let Some(paths) = paths.await.log_err().flatten() {
                 let results = this
-                    .update_in(&mut cx, |this, window, cx| {
+                    .update_in(cx, |this, window, cx| {
                         this.open_paths(
                             paths,
                             OpenOptions {
@@ -2320,9 +2313,9 @@ impl Workspace {
         let entry = project.update(cx, |project, cx| {
             project.find_or_create_worktree(abs_path, visible, cx)
         });
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |cx| {
             let (worktree, path) = entry.await?;
-            let worktree_id = worktree.update(&mut cx, |t, _| t.id())?;
+            let worktree_id = worktree.update(cx, |t, _| t.id())?;
             Ok((
                 worktree,
                 ProjectPath {
@@ -2374,7 +2367,7 @@ impl Workspace {
         let item = pane.read(cx).active_item();
         let pane = pane.downgrade();
 
-        window.spawn(cx, |mut cx| async move {
+        window.spawn(cx, async move |mut cx| {
             if let Some(item) = item {
                 Pane::save_item(project, &pane, item.as_ref(), save_intent, &mut cx)
                     .await
@@ -2465,7 +2458,7 @@ impl Workspace {
         if tasks.is_empty() {
             None
         } else {
-            Some(cx.spawn_in(window, |_, _| async move {
+            Some(cx.spawn_in(window, async move |_, _| {
                 for task in tasks {
                     task.await?
                 }
@@ -2795,9 +2788,9 @@ impl Workspace {
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> Task<anyhow::Result<Box<dyn ItemHandle>>> {
-        cx.spawn_in(window, |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             let open_paths_task_result = workspace
-                .update_in(&mut cx, |workspace, window, cx| {
+                .update_in(cx, |workspace, window, cx| {
                     workspace.open_paths(vec![abs_path.clone()], options, None, window, cx)
                 })
                 .with_context(|| format!("open abs path {abs_path:?} task spawn"))?
@@ -2828,12 +2821,10 @@ impl Workspace {
     ) -> Task<anyhow::Result<Box<dyn ItemHandle>>> {
         let project_path_task =
             Workspace::project_path_for_path(self.project.clone(), &abs_path, visible, cx);
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let (_, path) = project_path_task.await?;
-            this.update_in(&mut cx, |this, window, cx| {
-                this.split_path(path, window, cx)
-            })?
-            .await
+            this.update_in(cx, |this, window, cx| this.split_path(path, window, cx))?
+                .await
         })
     }
 
@@ -2868,9 +2859,9 @@ impl Workspace {
         });
 
         let task = self.load_path(path.into(), window, cx);
-        window.spawn(cx, move |mut cx| async move {
+        window.spawn(cx, async move |cx| {
             let (project_entry_id, build_item) = task.await?;
-            let result = pane.update_in(&mut cx, |pane, window, cx| {
+            let result = pane.update_in(cx, |pane, window, cx| {
                 let result = pane.open_item(
                     project_entry_id,
                     focus_item,
@@ -2919,9 +2910,9 @@ impl Workspace {
         }
 
         let task = self.load_path(path.into(), window, cx);
-        cx.spawn_in(window, |this, mut cx| async move {
+        cx.spawn_in(window, async move |this, cx| {
             let (project_entry_id, build_item) = task.await?;
-            this.update_in(&mut cx, move |this, window, cx| -> Option<_> {
+            this.update_in(cx, move |this, window, cx| -> Option<_> {
                 let pane = pane.upgrade()?;
                 let new_pane = this.split_pane(
                     pane,
@@ -3697,9 +3688,9 @@ impl Workspace {
             leader_id: Some(leader_id),
         });
 
-        Some(cx.spawn_in(window, |this, mut cx| async move {
+        Some(cx.spawn_in(window, async move |this, cx| {
             let response = request.await?;
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 let state = this
                     .follower_states
                     .get_mut(&leader_id)
@@ -3711,9 +3702,9 @@ impl Workspace {
                 Ok::<_, anyhow::Error>(())
             })??;
             if let Some(view) = response.active_view {
-                Self::add_view_from_leader(this.clone(), leader_id, &view, &mut cx).await?;
+                Self::add_view_from_leader(this.clone(), leader_id, &view, cx).await?;
             }
-            this.update_in(&mut cx, |this, window, cx| {
+            this.update_in(cx, |this, window, cx| {
                 this.leader_updated(leader_id, window, cx)
             })?;
             Ok(())
@@ -4525,11 +4516,11 @@ impl Workspace {
 
     fn serialize_workspace(&mut self, window: &mut Window, cx: &mut Context<Self>) {
         if self._schedule_serialize.is_none() {
-            self._schedule_serialize = Some(cx.spawn_in(window, |this, mut cx| async move {
+            self._schedule_serialize = Some(cx.spawn_in(window, async move |this, cx| {
                 cx.background_executor()
                     .timer(Duration::from_millis(100))
                     .await;
-                this.update_in(&mut cx, |this, window, cx| {
+                this.update_in(cx, |this, window, cx| {
                     this.serialize_workspace_internal(window, cx).detach();
                     this._schedule_serialize.take();
                 })
@@ -4683,7 +4674,9 @@ impl Workspace {
                 breakpoints,
                 window_id: Some(window.window_handle().window_id().as_u64()),
             };
-            return window.spawn(cx, |_| persistence::DB.save_workspace(serialized_workspace));
+            return window.spawn(cx, async move |_| {
+                persistence::DB.save_workspace(serialized_workspace).await
+            });
         }
         Task::ready(())
     }
@@ -4740,8 +4733,8 @@ impl Workspace {
         window: &mut Window,
         cx: &mut Context<Workspace>,
     ) -> Task<Result<Vec<Option<Box<dyn ItemHandle>>>>> {
-        cx.spawn_in(window, |workspace, mut cx| async move {
-            let project = workspace.update(&mut cx, |workspace, _| workspace.project().clone())?;
+        cx.spawn_in(window, async move |workspace, cx| {
+            let project = workspace.update(cx, |workspace, _| workspace.project().clone())?;
 
             let mut center_group = None;
             let mut center_items = None;
@@ -4749,12 +4742,7 @@ impl Workspace {
             // Traverse the splits tree and add to things
             if let Some((group, active_pane, items)) = serialized_workspace
                 .center_group
-                .deserialize(
-                    &project,
-                    serialized_workspace.id,
-                    workspace.clone(),
-                    &mut cx,
-                )
+                .deserialize(&project, serialized_workspace.id, workspace.clone(), cx)
                 .await
             {
                 center_items = Some(items);
@@ -4789,7 +4777,7 @@ impl Workspace {
                 .collect::<Vec<_>>();
 
             // Remove old panes from workspace panes list
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in(cx, |workspace, window, cx| {
                 if let Some((center_group, active_pane)) = center_group {
                     workspace.remove_panes(workspace.center.root.clone(), window, cx);
 
@@ -4822,7 +4810,7 @@ impl Workspace {
             })?;
 
             let _ = project
-                .update(&mut cx, |project, cx| {
+                .update(cx, |project, cx| {
                     project
                         .breakpoint_store()
                         .update(cx, |breakpoint_store, cx| {
@@ -4837,7 +4825,7 @@ impl Workspace {
             // the database filling up, we delete items that haven't been loaded now.
             //
             // The items that have been loaded, have been saved after they've been added to the workspace.
-            let clean_up_tasks = workspace.update_in(&mut cx, |_, window, cx| {
+            let clean_up_tasks = workspace.update_in(cx, |_, window, cx| {
                 item_ids_by_kind
                     .into_iter()
                     .map(|(item_kind, loaded_items)| {
@@ -4856,7 +4844,7 @@ impl Workspace {
             futures::future::join_all(clean_up_tasks).await;
 
             workspace
-                .update_in(&mut cx, |workspace, window, cx| {
+                .update_in(cx, |workspace, window, cx| {
                     // Serialize ourself to make sure our timestamps and any pane / item changes are replicated
                     workspace.serialize_workspace_internal(window, cx).detach();
 
@@ -5213,7 +5201,7 @@ fn open_items(
         )
     });
 
-    cx.spawn_in(window, |workspace, mut cx| async move {
+    cx.spawn_in(window, async move |workspace, cx| {
         let mut opened_items = Vec::with_capacity(project_paths_to_open.len());
 
         if let Some(restored_items) = restored_items {
@@ -5254,9 +5242,9 @@ fn open_items(
                 .enumerate()
                 .map(|(ix, (abs_path, project_path))| {
                     let workspace = workspace.clone();
-                    cx.spawn(|mut cx| async move {
+                    cx.spawn(async move |cx| {
                         let file_project_path = project_path?;
-                        let abs_path_task = workspace.update(&mut cx, |workspace, cx| {
+                        let abs_path_task = workspace.update(cx, |workspace, cx| {
                             workspace.project().update(cx, |project, cx| {
                                 project.resolve_abs_path(abs_path.to_string_lossy().as_ref(), cx)
                             })
@@ -5270,7 +5258,7 @@ fn open_items(
                                 return Some((
                                     ix,
                                     workspace
-                                        .update_in(&mut cx, |workspace, window, cx| {
+                                        .update_in(cx, |workspace, window, cx| {
                                             workspace.open_path(
                                                 file_project_path,
                                                 None,
@@ -5893,8 +5881,8 @@ async fn join_channel_internal(
                     }
                 });
                 if let Ok(Some(project)) = project {
-                    return Some(cx.spawn(|room, mut cx| async move {
-                        room.update(&mut cx, |room, cx| room.share_project(project, cx))?
+                    return Some(cx.spawn(async move |room, cx| {
+                        room.update(cx, |room, cx| room.share_project(project, cx))?
                             .await?;
                         Ok(())
                     }));
@@ -5918,13 +5906,13 @@ pub fn join_channel(
     cx: &mut App,
 ) -> Task<Result<()>> {
     let active_call = ActiveCall::global(cx);
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         let result = join_channel_internal(
             channel_id,
             &app_state,
             requesting_window,
             &active_call,
-            &mut cx,
+             cx,
         )
             .await;
 
@@ -5935,7 +5923,7 @@ pub fn join_channel(
 
         // find an existing workspace to focus and show call controls
         let mut active_window =
-            requesting_window.or_else(|| activate_any_workspace_window(&mut cx));
+            requesting_window.or_else(|| activate_any_workspace_window( cx));
         if active_window.is_none() {
             // no open workspaces, make one to show the error in (blergh)
             let (window_handle, _) = cx
@@ -5957,7 +5945,7 @@ pub fn join_channel(
             log::error!("failed to join channel: {}", err);
             if let Some(active_window) = active_window {
                 active_window
-                    .update(&mut cx, |_, window, cx| {
+                    .update(cx, |_, window, cx| {
                         let detail: SharedString = match err.error_code() {
                             ErrorCode::SignedOut => {
                                 "Please sign in to continue.".into()
@@ -6065,7 +6053,7 @@ pub fn open_paths(
     let mut best_match = None;
     let mut open_visible = OpenVisible::All;
 
-    cx.spawn(move |mut cx| async move {
+    cx.spawn(async move |cx| {
         if open_options.open_new_workspace != Some(true) {
             let all_paths = abs_paths.iter().map(|path| app_state.fs.metadata(path));
             let all_metadatas = futures::future::join_all(all_paths)
@@ -6129,7 +6117,7 @@ pub fn open_paths(
 
         if let Some(existing) = existing {
             let open_task = existing
-                .update(&mut cx, |workspace, window, cx| {
+                .update(cx, |workspace, window, cx| {
                     window.activate_window();
                     workspace.open_paths(
                         abs_paths,
@@ -6144,7 +6132,7 @@ pub fn open_paths(
                 })?
                 .await;
 
-            _ = existing.update(&mut cx, |workspace, _, cx| {
+            _ = existing.update(cx, |workspace, _, cx| {
                 for item in open_task.iter().flatten() {
                     if let Err(e) = item {
                         workspace.show_error(&e, cx);
@@ -6175,9 +6163,9 @@ pub fn open_new(
     init: impl FnOnce(&mut Workspace, &mut Window, &mut Context<Workspace>) + 'static + Send,
 ) -> Task<anyhow::Result<()>> {
     let task = Workspace::new_local(Vec::new(), app_state, None, open_options.env, cx);
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         let (workspace, opened_paths) = task.await?;
-        workspace.update(&mut cx, |workspace, window, cx| {
+        workspace.update(cx, |workspace, window, cx| {
             if opened_paths.is_empty() {
                 init(workspace, window, cx)
             }
@@ -6192,8 +6180,8 @@ pub fn create_and_open_local_file(
     cx: &mut Context<Workspace>,
     default_content: impl 'static + Send + FnOnce() -> Rope,
 ) -> Task<Result<Box<dyn ItemHandle>>> {
-    cx.spawn_in(window, |workspace, mut cx| async move {
-        let fs = workspace.update(&mut cx, |workspace, _| workspace.app_state().fs.clone())?;
+    cx.spawn_in(window, async move |workspace, cx| {
+        let fs = workspace.update(cx, |workspace, _| workspace.app_state().fs.clone())?;
         if !fs.is_file(path).await {
             fs.create_file(path, Default::default()).await?;
             fs.save(path, &default_content(), Default::default())
@@ -6201,7 +6189,7 @@ pub fn create_and_open_local_file(
         }
 
         let mut items = workspace
-            .update_in(&mut cx, |workspace, window, cx| {
+            .update_in(cx, |workspace, window, cx| {
                 workspace.with_local_workspace(window, cx, |workspace, window, cx| {
                     workspace.open_paths(
                         vec![path.to_path_buf()],
@@ -6232,7 +6220,7 @@ pub fn open_ssh_project(
     paths: Vec<PathBuf>,
     cx: &mut App,
 ) -> Task<Result<()>> {
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         let (serialized_ssh_project, workspace_id, serialized_workspace) =
             serialize_ssh_project(connection_options.clone(), paths.clone(), &cx).await?;
 
@@ -6267,7 +6255,7 @@ pub fn open_ssh_project(
         let toolchains = DB.toolchains(workspace_id).await?;
         for (toolchain, worktree_id) in toolchains {
             project
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     this.activate_toolchain(worktree_id, toolchain, cx)
                 })?
                 .await;
@@ -6307,14 +6295,14 @@ pub fn open_ssh_project(
         })?;
 
         window
-            .update(&mut cx, |_, window, cx| {
+            .update(cx, |_, window, cx| {
                 window.activate_window();
 
                 open_items(serialized_workspace, project_paths_to_open, window, cx)
             })?
             .await?;
 
-        window.update(&mut cx, |workspace, _, cx| {
+        window.update(cx, |workspace, _, cx| {
             for error in project_path_errors {
                 if error.error_code() == proto::ErrorCode::DevServerProjectPathDoesNotExist {
                     if let Some(path) = error.error_tag("path") {
@@ -6374,13 +6362,13 @@ pub fn join_in_room_project(
     cx: &mut App,
 ) -> Task<Result<()>> {
     let windows = cx.windows();
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         let existing_workspace = windows.into_iter().find_map(|window_handle| {
             window_handle
                 .downcast::<Workspace>()
                 .and_then(|window_handle| {
                     window_handle
-                        .update(&mut cx, |workspace, _window, cx| {
+                        .update(cx, |workspace, _window, cx| {
                             if workspace.project().read(cx).remote_id() == Some(project_id) {
                                 Some(window_handle)
                             } else {
@@ -6396,10 +6384,10 @@ pub fn join_in_room_project(
         } else {
             let active_call = cx.update(|cx| ActiveCall::global(cx))?;
             let room = active_call
-                .read_with(&cx, |call, _| call.room().cloned())?
+                .read_with(cx, |call, _| call.room().cloned())?
                 .ok_or_else(|| anyhow!("not in a call"))?;
             let project = room
-                .update(&mut cx, |room, cx| {
+                .update(cx, |room, cx| {
                     room.join_project(
                         project_id,
                         app_state.languages.clone(),
@@ -6421,7 +6409,7 @@ pub fn join_in_room_project(
             })??
         };
 
-        workspace.update(&mut cx, |workspace, window, cx| {
+        workspace.update(cx, |workspace, window, cx| {
             cx.activate(true);
             window.activate_window();
 
@@ -6481,7 +6469,7 @@ pub fn reload(reload: &Reload, cx: &mut App) {
     }
 
     let binary_path = reload.binary_path.clone();
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         if let Some(prompt) = prompt {
             let answer = prompt.await?;
             if answer != 0 {
@@ -6491,7 +6479,7 @@ pub fn reload(reload: &Reload, cx: &mut App) {
 
         // If the user cancels any save prompt, then keep the app open.
         for window in workspace_windows {
-            if let Ok(should_close) = window.update(&mut cx, |workspace, window, cx| {
+            if let Ok(should_close) = window.update(cx, |workspace, window, cx| {
                 workspace.prepare_to_close(CloseIntent::Quit, window, cx)
             }) {
                 if !should_close.await? {
@@ -8639,7 +8627,7 @@ mod tests {
                 cx: &mut App,
             ) -> Option<Task<gpui::Result<Entity<Self>>>> {
                 if path.path.extension().unwrap() == "png" {
-                    Some(cx.spawn(|mut cx| async move { cx.new(|_| TestPngItem {}) }))
+                    Some(cx.spawn(async move |cx| cx.new(|_| TestPngItem {})))
                 } else {
                     None
                 }
@@ -8710,7 +8698,7 @@ mod tests {
                 cx: &mut App,
             ) -> Option<Task<gpui::Result<Entity<Self>>>> {
                 if path.path.extension().unwrap() == "ipynb" {
-                    Some(cx.spawn(|mut cx| async move { cx.new(|_| TestIpynbItem {}) }))
+                    Some(cx.spawn(async move |cx| cx.new(|_| TestIpynbItem {})))
                 } else {
                     None
                 }

crates/worktree/src/worktree.rs 🔗

@@ -854,9 +854,9 @@ impl Worktree {
 
             // On the foreground task, update to the latest snapshot and notify
             // any update observer of all updates that led to that snapshot.
-            cx.spawn(|this, mut cx| async move {
+            cx.spawn(async move |this, cx| {
                 while (snapshot_updated_rx.recv().await).is_some() {
-                    this.update(&mut cx, |this, cx| {
+                    this.update(cx, |this, cx| {
                         let mut git_repos_changed = false;
                         let mut entries_changed = false;
                         let this = this.as_remote_mut().unwrap();
@@ -1052,13 +1052,16 @@ impl Worktree {
             Worktree::Local(this) => {
                 let path = Arc::from(path);
                 let snapshot = this.snapshot();
-                cx.spawn(|cx| async move {
+                cx.spawn(async move |cx| {
                     if let Some(repo) = snapshot.repository_for_path(&path) {
                         if let Some(repo_path) = repo.relativize(&path).log_err() {
                             if let Some(git_repo) =
                                 snapshot.git_repositories.get(&repo.work_directory_id)
                             {
-                                return Ok(git_repo.repo_ptr.load_index_text(repo_path, cx).await);
+                                return Ok(git_repo
+                                    .repo_ptr
+                                    .load_index_text(repo_path, cx.clone())
+                                    .await);
                             }
                         }
                     }
@@ -1076,7 +1079,7 @@ impl Worktree {
             Worktree::Local(this) => {
                 let path = Arc::from(path);
                 let snapshot = this.snapshot();
-                cx.spawn(|cx| async move {
+                cx.spawn(async move |cx| {
                     if let Some(repo) = snapshot.repository_for_path(&path) {
                         if let Some(repo_path) = repo.relativize(&path).log_err() {
                             if let Some(git_repo) =
@@ -1084,7 +1087,7 @@ impl Worktree {
                             {
                                 return Ok(git_repo
                                     .repo_ptr
-                                    .load_committed_text(repo_path, cx)
+                                    .load_committed_text(repo_path, cx.clone())
                                     .await);
                             }
                         }
@@ -1144,11 +1147,11 @@ impl Worktree {
                     path: path.as_ref().to_proto(),
                     is_directory,
                 });
-                cx.spawn(move |this, mut cx| async move {
+                cx.spawn(async move |this, cx| {
                     let response = request.await?;
                     match response.entry {
                         Some(entry) => this
-                            .update(&mut cx, |worktree, cx| {
+                            .update(cx, |worktree, cx| {
                                 worktree.as_remote_mut().unwrap().insert_entry(
                                     entry,
                                     response.worktree_scan_id as usize,
@@ -1158,7 +1161,7 @@ impl Worktree {
                             .await
                             .map(CreatedEntry::Included),
                         None => {
-                            let abs_path = this.update(&mut cx, |worktree, _| {
+                            let abs_path = this.update(cx, |worktree, _| {
                                 worktree
                                     .absolutize(&path)
                                     .with_context(|| format!("absolutizing {path:?}"))
@@ -1240,11 +1243,11 @@ impl Worktree {
                     relative_worktree_source_path,
                     new_path: new_path.to_proto(),
                 });
-                cx.spawn(move |this, mut cx| async move {
+                cx.spawn(async move |this, cx| {
                     let response = response.await?;
                     match response.entry {
                         Some(entry) => this
-                            .update(&mut cx, |worktree, cx| {
+                            .update(cx, |worktree, cx| {
                                 worktree.as_remote_mut().unwrap().insert_entry(
                                     entry,
                                     response.worktree_scan_id as usize,
@@ -1289,9 +1292,9 @@ impl Worktree {
                     project_id: this.project_id,
                     entry_id: entry_id.to_proto(),
                 });
-                Some(cx.spawn(move |this, mut cx| async move {
+                Some(cx.spawn(async move |this, cx| {
                     let response = response.await?;
-                    this.update(&mut cx, |this, _| {
+                    this.update(cx, |this, _| {
                         this.as_remote_mut()
                             .unwrap()
                             .wait_for_snapshot(response.worktree_scan_id as usize)
@@ -1315,9 +1318,9 @@ impl Worktree {
                     project_id: this.project_id,
                     entry_id: entry_id.to_proto(),
                 });
-                Some(cx.spawn(move |this, mut cx| async move {
+                Some(cx.spawn(async move |this, cx| {
                     let response = response.await?;
-                    this.update(&mut cx, |this, _| {
+                    this.update(cx, |this, _| {
                         this.as_remote_mut()
                             .unwrap()
                             .wait_for_snapshot(response.worktree_scan_id as usize)
@@ -1549,9 +1552,9 @@ impl LocalWorktree {
                     .await;
             }
         });
-        let scan_state_updater = cx.spawn(|this, mut cx| async move {
+        let scan_state_updater = cx.spawn(async move |this, cx| {
             while let Some((state, this)) = scan_states_rx.next().await.zip(this.upgrade()) {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     let this = this.as_local_mut().unwrap();
                     match state {
                         ScanState::Started => {
@@ -1786,7 +1789,7 @@ impl LocalWorktree {
         let entry = self.refresh_entry(path.clone(), None, cx);
         let is_private = self.is_path_private(path.as_ref());
 
-        cx.spawn(|this, _cx| async move {
+        cx.spawn(async move |this, _cx| {
             let abs_path = abs_path?;
             let text = fs.load(&abs_path).await?;
 
@@ -1862,13 +1865,13 @@ impl LocalWorktree {
         });
 
         let lowest_ancestor = self.lowest_ancestor(&path);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             write.await?;
             if path_excluded {
                 return Ok(CreatedEntry::Excluded { abs_path });
             }
 
-            let (result, refreshes) = this.update(&mut cx, |this, cx| {
+            let (result, refreshes) = this.update(cx, |this, cx| {
                 let mut refreshes = Vec::new();
                 let refresh_paths = path.strip_prefix(&lowest_ancestor).unwrap();
                 for refresh_path in refresh_paths.ancestors() {
@@ -1919,10 +1922,10 @@ impl LocalWorktree {
             async move { fs.save(&abs_path, &text, line_ending).await }
         });
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             write.await?;
             let entry = this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     this.as_local_mut()
                         .unwrap()
                         .refresh_entry(path.clone(), None, cx)
@@ -1994,9 +1997,9 @@ impl LocalWorktree {
             anyhow::Ok(entry.path)
         });
 
-        Some(cx.spawn(|this, mut cx| async move {
+        Some(cx.spawn(async move |this, cx| {
             let path = delete.await?;
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 this.as_local_mut()
                     .unwrap()
                     .refresh_entries_for_paths(vec![path])
@@ -2064,10 +2067,10 @@ impl LocalWorktree {
             .with_context(|| format!("Renaming {abs_old_path:?} into {abs_new_path:?}"))
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             rename.await?;
             Ok(this
-                .update(&mut cx, |this, cx| {
+                .update(cx, |this, cx| {
                     let local = this.as_local_mut().unwrap();
                     if is_root_entry {
                         // We eagerly update `abs_path` and refresh this worktree.
@@ -2118,9 +2121,9 @@ impl LocalWorktree {
             .await
         });
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             copy.await?;
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.as_local_mut()
                     .unwrap()
                     .refresh_entry(new_path.clone(), None, cx)
@@ -2159,7 +2162,7 @@ impl LocalWorktree {
             .filter_map(|(_, target)| Some(target.strip_prefix(&worktree_path).ok()?.into()))
             .collect::<Vec<_>>();
 
-        cx.spawn(|this, cx| async move {
+        cx.spawn(async move |this, cx| {
             cx.background_spawn(async move {
                 for (source, target) in paths {
                     copy_recursive(
@@ -2272,10 +2275,10 @@ impl LocalWorktree {
         };
         let t0 = Instant::now();
         let mut refresh = self.refresh_entries_for_paths(paths);
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             refresh.recv().await;
             log::trace!("refreshed entry {path:?} in {:?}", t0.elapsed());
-            let new_entry = this.update(&mut cx, |this, _| {
+            let new_entry = this.update(cx, |this, _| {
                 this.entry_for_path(path)
                     .cloned()
                     .ok_or_else(|| anyhow!("failed to read path after update"))
@@ -2393,7 +2396,7 @@ impl RemoteWorktree {
             .snapshot
             .build_initial_update(project_id, self.id().to_proto());
         self.update_observer = Some(tx);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let mut update = initial_update;
             'outer: loop {
                 // SSH projects use a special project ID of 0, and we need to
@@ -2412,7 +2415,7 @@ impl RemoteWorktree {
                     break;
                 }
             }
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 let this = this.as_remote_mut().unwrap();
                 this.update_observer.take();
             })
@@ -2452,9 +2455,9 @@ impl RemoteWorktree {
         cx: &Context<Worktree>,
     ) -> Task<Result<Entry>> {
         let wait_for_snapshot = self.wait_for_snapshot(scan_id);
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             wait_for_snapshot.await?;
-            this.update(&mut cx, |worktree, _| {
+            this.update(cx, |worktree, _| {
                 let worktree = worktree.as_remote_mut().unwrap();
                 let snapshot = &mut worktree.background_snapshot.lock().0;
                 let entry = snapshot.insert_entry(entry, &worktree.file_scan_inclusions);
@@ -2475,16 +2478,16 @@ impl RemoteWorktree {
             entry_id: entry_id.to_proto(),
             use_trash: trash,
         });
-        Some(cx.spawn(move |this, mut cx| async move {
+        Some(cx.spawn(async move |this, cx| {
             let response = response.await?;
             let scan_id = response.worktree_scan_id as usize;
 
-            this.update(&mut cx, move |this, _| {
+            this.update(cx, move |this, _| {
                 this.as_remote_mut().unwrap().wait_for_snapshot(scan_id)
             })?
             .await?;
 
-            this.update(&mut cx, |this, _| {
+            this.update(cx, |this, _| {
                 let this = this.as_remote_mut().unwrap();
                 let snapshot = &mut this.background_snapshot.lock().0;
                 snapshot.delete_entry(entry_id);
@@ -2505,11 +2508,11 @@ impl RemoteWorktree {
             entry_id: entry_id.to_proto(),
             new_path: new_path.as_ref().to_proto(),
         });
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let response = response.await?;
             match response.entry {
                 Some(entry) => this
-                    .update(&mut cx, |this, cx| {
+                    .update(cx, |this, cx| {
                         this.as_remote_mut().unwrap().insert_entry(
                             entry,
                             response.worktree_scan_id as usize,
@@ -2519,7 +2522,7 @@ impl RemoteWorktree {
                     .await
                     .map(CreatedEntry::Included),
                 None => {
-                    let abs_path = this.update(&mut cx, |worktree, _| {
+                    let abs_path = this.update(cx, |worktree, _| {
                         worktree
                             .absolutize(&new_path)
                             .with_context(|| format!("absolutizing {new_path:?}"))

crates/zed/src/main.rs 🔗

@@ -109,7 +109,7 @@ fn files_not_created_on_launch(errors: HashMap<io::ErrorKind, Vec<&Path>>) {
                         cx,
                     );
 
-                    cx.spawn_in(window, |_, mut cx| async move {
+                    cx.spawn_in(window, async move |_, cx| {
                         response.await?;
                         cx.update(|_, cx| cx.quit())
                     })
@@ -138,7 +138,7 @@ fn fail_to_open_window(e: anyhow::Error, _cx: &mut App) {
     #[cfg(any(target_os = "linux", target_os = "freebsd"))]
     {
         use ashpd::desktop::notification::{Notification, NotificationProxy, Priority};
-        _cx.spawn(|_cx| async move {
+        _cx.spawn(async move |_cx| {
             let Ok(proxy) = NotificationProxy::new().await else {
                 process::exit(1);
             };
@@ -285,7 +285,7 @@ fn main() {
         {
             cx.spawn({
                 let app_state = app_state.clone();
-                |mut cx| async move {
+                async move |mut cx| {
                     if let Err(e) = restore_or_create_workspace(app_state, &mut cx).await {
                         fail_to_open_window_async(e, &mut cx)
                     }
@@ -580,7 +580,7 @@ fn main() {
 
         cx.spawn({
             let client = app_state.client.clone();
-            |cx| async move { authenticate(client, &cx).await }
+            async move |cx| authenticate(client, &cx).await
         })
         .detach_and_log_err(cx);
 
@@ -606,7 +606,7 @@ fn main() {
             None => {
                 cx.spawn({
                     let app_state = app_state.clone();
-                    |mut cx| async move {
+                    async move |mut cx| {
                         if let Err(e) = restore_or_create_workspace(app_state, &mut cx).await {
                             fail_to_open_window_async(e, &mut cx)
                         }
@@ -620,7 +620,7 @@ fn main() {
 
         component_preview::init(app_state.clone(), cx);
 
-        cx.spawn(move |cx| async move {
+        cx.spawn(async move |cx| {
             while let Some(urls) = open_rx.next().await {
                 cx.update(|cx| {
                     if let Some(request) = OpenRequest::parse(urls, cx).log_err() {
@@ -637,7 +637,7 @@ fn main() {
 fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut App) {
     if let Some(connection) = request.cli_connection {
         let app_state = app_state.clone();
-        cx.spawn(move |cx| handle_cli_connection(connection, app_state, cx))
+        cx.spawn(async move |cx| handle_cli_connection(connection, app_state, cx).await)
             .detach();
         return;
     }
@@ -648,7 +648,7 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
     }
 
     if let Some(connection_options) = request.ssh_connection {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |mut cx| {
             let paths_with_position =
                 derive_paths_with_position(app_state.fs.as_ref(), request.open_paths).await;
             open_ssh_project(
@@ -667,7 +667,7 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
     let mut task = None;
     if !request.open_paths.is_empty() {
         let app_state = app_state.clone();
-        task = Some(cx.spawn(|mut cx| async move {
+        task = Some(cx.spawn(async move |mut cx| {
             let paths_with_position =
                 derive_paths_with_position(app_state.fs.as_ref(), request.open_paths).await;
             let (_window, results) = open_paths_with_positions(
@@ -687,7 +687,7 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
     }
 
     if !request.open_channel_notes.is_empty() || request.join_channel.is_some() {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |mut cx| {
             let result = maybe!(async {
                 if let Some(task) = task {
                     task.await?;
@@ -711,7 +711,7 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
 
                 let workspace_window =
                     workspace::get_any_active_workspace(app_state, cx.clone()).await?;
-                let workspace = workspace_window.entity(&cx)?;
+                let workspace = workspace_window.entity(cx)?;
 
                 let mut promises = Vec::new();
                 for (channel_id, heading) in request.open_channel_notes {
@@ -736,7 +736,7 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
         })
         .detach()
     } else if let Some(task) = task {
-        cx.spawn(|mut cx| async move {
+        cx.spawn(async move |mut cx| {
             if let Err(err) = task.await {
                 fail_to_open_window_async(err, &mut cx);
             }
@@ -821,13 +821,13 @@ async fn restore_or_create_workspace(app_state: Arc<AppState>, cx: &mut AsyncApp
                             .connection_options_for(ssh.host, ssh.port, ssh.user)
                     })?;
                     let app_state = app_state.clone();
-                    cx.spawn(move |mut cx| async move {
+                    cx.spawn(async move |cx| {
                         recent_projects::open_ssh_project(
                             connection_options,
                             ssh.paths.into_iter().map(PathBuf::from).collect(),
                             app_state,
                             workspace::OpenOptions::default(),
-                            &mut cx,
+                            cx,
                         )
                         .await
                         .log_err();
@@ -1040,7 +1040,7 @@ fn eager_load_active_theme_and_icon_theme(fs: Arc<dyn Fs>, cx: &App) {
                 cx.spawn({
                     let theme_registry = theme_registry.clone();
                     let fs = fs.clone();
-                    |cx| async move {
+                    async move |cx| {
                         theme_registry.load_user_theme(&theme_path, fs).await?;
 
                         cx.update(|cx| {
@@ -1066,7 +1066,7 @@ fn eager_load_active_theme_and_icon_theme(fs: Arc<dyn Fs>, cx: &App) {
                 cx.spawn({
                     let theme_registry = theme_registry.clone();
                     let fs = fs.clone();
-                    |cx| async move {
+                    async move |cx| {
                         theme_registry
                             .load_icon_theme(&icon_theme_path, &icons_root_path, fs)
                             .await?;
@@ -1086,7 +1086,7 @@ fn eager_load_active_theme_and_icon_theme(fs: Arc<dyn Fs>, cx: &App) {
 fn load_user_themes_in_background(fs: Arc<dyn fs::Fs>, cx: &mut App) {
     cx.spawn({
         let fs = fs.clone();
-        |cx| async move {
+        async move |cx| {
             if let Some(theme_registry) =
                 cx.update(|cx| ThemeRegistry::global(cx).clone()).log_err()
             {
@@ -1119,7 +1119,7 @@ fn load_user_themes_in_background(fs: Arc<dyn fs::Fs>, cx: &mut App) {
 /// Spawns a background task to watch the themes directory for changes.
 fn watch_themes(fs: Arc<dyn fs::Fs>, cx: &mut App) {
     use std::time::Duration;
-    cx.spawn(|cx| async move {
+    cx.spawn(async move |cx| {
         let (mut events, _) = fs
             .watch(paths::themes_dir(), Duration::from_millis(100))
             .await;
@@ -1157,7 +1157,7 @@ fn watch_languages(fs: Arc<dyn fs::Fs>, languages: Arc<LanguageRegistry>, cx: &m
         full_path
     };
 
-    cx.spawn(|_| async move {
+    cx.spawn(async move |_| {
         let (mut events, _) = fs.watch(path.as_path(), Duration::from_millis(100)).await;
         while let Some(event) = events.next().await {
             let has_language_file = event.iter().any(|event| {

crates/zed/src/zed.rs 🔗

@@ -26,10 +26,10 @@ use futures::{channel::mpsc, select_biased, StreamExt};
 use git_ui::git_panel::GitPanel;
 use git_ui::project_diff::ProjectDiffToolbar;
 use gpui::{
-    actions, point, px, Action, App, AppContext as _, AsyncApp, Context, DismissEvent, Element,
-    Entity, Focusable, KeyBinding, MenuItem, ParentElement, PathPromptOptions, PromptLevel,
-    ReadGlobal, SharedString, Styled, Task, TitlebarOptions, UpdateGlobal, Window, WindowKind,
-    WindowOptions,
+    actions, point, px, Action, App, AppContext as _, AsyncApp, AsyncWindowContext, Context,
+    DismissEvent, Element, Entity, Focusable, KeyBinding, MenuItem, ParentElement,
+    PathPromptOptions, PromptLevel, ReadGlobal, SharedString, Styled, Task, TitlebarOptions,
+    UpdateGlobal, Window, WindowKind, WindowOptions,
 };
 use image_viewer::ImageInfo;
 use migrate::{MigrationBanner, MigrationEvent, MigrationNotification, MigrationType};
@@ -307,7 +307,7 @@ fn initialize_file_watcher(window: &mut Window, cx: &mut Context<Workspace>) {
             &["Troubleshoot and Quit"],
             cx,
         );
-        cx.spawn(|_, cx| async move {
+        cx.spawn(async move |_, cx| {
             if prompt.await == Ok(0) {
                 cx.update(|cx| {
                     cx.open_url("https://zed.dev/docs/linux#could-not-start-inotify");
@@ -338,7 +338,7 @@ fn initialize_file_watcher(window: &mut Window, cx: &mut Context<Workspace>) {
             &["Troubleshoot and Quit"],
             cx,
         );
-        cx.spawn(|_, cx| async move {
+        cx.spawn(async move |_, cx| {
             if prompt.await == Ok(0) {
                 cx.update(|cx| {
                     cx.open_url("https://zed.dev/docs/windows");
@@ -376,7 +376,7 @@ fn show_software_emulation_warning_if_needed(
             &["Skip", "Troubleshoot and Quit"],
             cx,
         );
-        cx.spawn(|_, cx| async move {
+        cx.spawn(async move |_, cx| {
             if prompt.await == Ok(1) {
                 cx.update(|cx| {
                     cx.open_url("https://zed.dev/docs/linux#zed-fails-to-open-windows");
@@ -399,7 +399,7 @@ fn initialize_panels(
 
     let prompt_builder = prompt_builder.clone();
 
-    cx.spawn_in(window, |workspace_handle, mut cx| async move {
+    cx.spawn_in(window, async move |workspace_handle, cx| {
         let project_panel = ProjectPanel::load(workspace_handle.clone(), cx.clone());
         let outline_panel = OutlinePanel::load(workspace_handle.clone(), cx.clone());
         let terminal_panel = TerminalPanel::load(workspace_handle.clone(), cx.clone());
@@ -428,7 +428,7 @@ fn initialize_panels(
             notification_panel,
         )?;
 
-        workspace_handle.update_in(&mut cx, |workspace, window, cx| {
+        workspace_handle.update_in(cx, |workspace, window, cx| {
             workspace.add_panel(project_panel, window, cx);
             workspace.add_panel(outline_panel, window, cx);
             workspace.add_panel(terminal_panel, window, cx);
@@ -436,13 +436,17 @@ fn initialize_panels(
             workspace.add_panel(chat_panel, window, cx);
             workspace.add_panel(notification_panel, window, cx);
             cx.when_flag_enabled::<Debugger>(window, |_, window, cx| {
-                cx.spawn_in(window, |workspace, mut cx| async move {
-                    let debug_panel = DebugPanel::load(workspace.clone(), cx.clone()).await?;
-                    workspace.update_in(&mut cx, |workspace, window, cx| {
-                        workspace.add_panel(debug_panel, window, cx);
-                    })?;
-                    Result::<_, anyhow::Error>::Ok(())
-                })
+                cx.spawn_in(
+                    window,
+                    async move |workspace: gpui::WeakEntity<Workspace>,
+                                cx: &mut AsyncWindowContext| {
+                        let debug_panel = DebugPanel::load(workspace.clone(), cx.clone()).await?;
+                        workspace.update_in(cx, |workspace, window, cx| {
+                            workspace.add_panel(debug_panel, window, cx);
+                        })?;
+                        Result::<_, anyhow::Error>::Ok(())
+                    },
+                )
                 .detach()
             });
 
@@ -479,7 +483,7 @@ fn initialize_panels(
             (Some(assistant_panel), None)
         };
 
-        workspace_handle.update_in(&mut cx, |workspace, window, cx| {
+        workspace_handle.update_in(cx, |workspace, window, cx| {
             if let Some(assistant2_panel) = assistant2_panel {
                 workspace.add_panel(assistant2_panel, window, cx);
             }
@@ -554,13 +558,13 @@ fn register_actions(
                 cx,
             );
 
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 let Some(paths) = paths.await.log_err().flatten() else {
                     return;
                 };
 
                 if let Some(task) = this
-                    .update_in(&mut cx, |this, window, cx| {
+                    .update_in(cx, |this, window, cx| {
                         if this.project().read(cx).is_local() {
                             this.open_workspace_for_paths(false, paths, window, cx)
                         } else {
@@ -670,9 +674,9 @@ fn register_actions(
         })
         .register_action(install_cli)
         .register_action(|_, _: &install_cli::RegisterZedScheme, window, cx| {
-            cx.spawn_in(window, |workspace, mut cx| async move {
+            cx.spawn_in(window, async move |workspace, cx| {
                 register_zed_scheme(&cx).await?;
-                workspace.update_in(&mut cx, |workspace, _, cx| {
+                workspace.update_in(cx, |workspace, _, cx| {
                     struct RegisterZedScheme;
 
                     workspace.show_toast(
@@ -870,11 +874,11 @@ fn register_actions(
                     .project()
                     .update(cx, |project, cx| project.open_server_settings(cx));
 
-                cx.spawn_in(window, |workspace, mut cx| async move {
+                cx.spawn_in(window, async move |workspace, cx| {
                     let buffer = open_server_settings.await?;
 
                     workspace
-                        .update_in(&mut cx, |workspace, window, cx| {
+                        .update_in(cx, |workspace, window, cx| {
                             workspace.open_path(
                                 buffer
                                     .read(cx)
@@ -975,7 +979,7 @@ fn install_cli(
 ) {
     const LINUX_PROMPT_DETAIL: &str = "If you installed Zed from our official release add ~/.local/bin to your PATH.\n\nIf you installed Zed from a different source like your package manager, then you may need to create an alias/symlink manually.\n\nDepending on your package manager, the CLI might be named zeditor, zedit, zed-editor or something else.";
 
-    cx.spawn_in(window, |workspace, mut cx| async move {
+    cx.spawn_in(window, async move |workspace, cx| {
         if cfg!(any(target_os = "linux", target_os = "freebsd")) {
             let prompt = cx.prompt(
                 PromptLevel::Warning,
@@ -990,7 +994,7 @@ fn install_cli(
             .await
             .context("error creating CLI symlink")?;
 
-        workspace.update_in(&mut cx, |workspace, _, cx| {
+        workspace.update_in(cx, |workspace, _, cx| {
             struct InstalledZedCli;
 
             workspace.show_toast(
@@ -1018,7 +1022,7 @@ fn quit(_: &Quit, cx: &mut App) {
     }
 
     let should_confirm = WorkspaceSettings::get_global(cx).confirm_quit;
-    cx.spawn(|mut cx| async move {
+    cx.spawn(async move |cx| {
         let mut workspace_windows = cx.update(|cx| {
             cx.windows()
                 .into_iter()
@@ -1036,7 +1040,7 @@ fn quit(_: &Quit, cx: &mut App) {
         if should_confirm {
             if let Some(workspace) = workspace_windows.first() {
                 let answer = workspace
-                    .update(&mut cx, |_, window, cx| {
+                    .update(cx, |_, window, cx| {
                         window.prompt(
                             PromptLevel::Info,
                             "Are you sure you want to quit?",
@@ -1061,7 +1065,7 @@ fn quit(_: &Quit, cx: &mut App) {
         // If the user cancels any save prompt, then keep the app open.
         for window in workspace_windows {
             if let Some(should_close) = window
-                .update(&mut cx, |workspace, window, cx| {
+                .update(cx, |workspace, window, cx| {
                     workspace.prepare_to_close(CloseIntent::Quit, window, cx)
                 })
                 .log_err()
@@ -1082,7 +1086,7 @@ fn open_log_file(workspace: &mut Workspace, window: &mut Window, cx: &mut Contex
     workspace
         .with_local_workspace(window, cx, move |workspace, window, cx| {
             let fs = workspace.app_state().fs.clone();
-            cx.spawn_in(window, |workspace, mut cx| async move {
+            cx.spawn_in(window, async move |workspace, cx| {
                 let (old_log, new_log) =
                     futures::join!(fs.load(paths::old_log_file()), fs.load(paths::log_file()));
                 let log = match (old_log, new_log) {
@@ -1109,7 +1113,7 @@ fn open_log_file(workspace: &mut Workspace, window: &mut Window, cx: &mut Contex
                 };
 
                 workspace
-                    .update_in(&mut cx, |workspace, window, cx| {
+                    .update_in(cx, |workspace, window, cx| {
                         let Some(log) = log else {
                             struct OpenLogError;
 
@@ -1189,7 +1193,7 @@ pub fn handle_settings_file_changes(
         }
         settings_changed(result.err(), cx);
     });
-    cx.spawn(move |cx| async move {
+    cx.spawn(async move |cx| {
         while let Some(content) = user_settings_file_rx.next().await {
             let user_settings_content;
             let content_migrated;
@@ -1267,7 +1271,7 @@ pub fn handle_keymap_file_changes(
     struct KeymapParseErrorNotification;
     let notification_id = NotificationId::unique::<KeymapParseErrorNotification>();
 
-    cx.spawn(move |cx| async move {
+    cx.spawn(async move |cx| {
         let mut user_keymap_content = String::new();
         let mut content_migrated = false;
         loop {
@@ -1377,7 +1381,7 @@ fn show_markdown_app_notification<F>(
         .await
     });
 
-    cx.spawn(move |cx| async move {
+    cx.spawn(async move |cx| {
         let parsed_markdown = Arc::new(parsed_markdown.await);
         let primary_button_message = primary_button_message.clone();
         let primary_button_on_click = Arc::new(primary_button_on_click);
@@ -1475,7 +1479,7 @@ pub fn open_new_ssh_project_from_project(
         return Task::ready(Err(anyhow::anyhow!("Not an ssh project")));
     };
     let connection_options = ssh_client.read(cx).connection_options();
-    cx.spawn_in(window, |_, mut cx| async move {
+    cx.spawn_in(window, async move |_, cx| {
         open_ssh_project(
             connection_options,
             paths,
@@ -1484,7 +1488,7 @@ pub fn open_new_ssh_project_from_project(
                 open_new_workspace: Some(true),
                 ..Default::default()
             },
-            &mut cx,
+            cx,
         )
         .await
     })
@@ -1549,11 +1553,11 @@ fn open_local_file(
         .find_map(|tree| tree.read(cx).root_entry()?.is_dir().then_some(tree));
     if let Some(worktree) = worktree {
         let tree_id = worktree.read(cx).id();
-        cx.spawn_in(window, |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             if let Some(dir_path) = settings_relative_path.parent() {
-                if worktree.update(&mut cx, |tree, _| tree.entry_for_path(dir_path).is_none())? {
+                if worktree.update(cx, |tree, _| tree.entry_for_path(dir_path).is_none())? {
                     project
-                        .update(&mut cx, |project, cx| {
+                        .update(cx, |project, cx| {
                             project.create_entry((tree_id, dir_path), true, cx)
                         })?
                         .await
@@ -1561,11 +1565,11 @@ fn open_local_file(
                 }
             }
 
-            if worktree.update(&mut cx, |tree, _| {
+            if worktree.update(cx, |tree, _| {
                 tree.entry_for_path(settings_relative_path).is_none()
             })? {
                 project
-                    .update(&mut cx, |project, cx| {
+                    .update(cx, |project, cx| {
                         project.create_entry((tree_id, settings_relative_path), false, cx)
                     })?
                     .await
@@ -1573,7 +1577,7 @@ fn open_local_file(
             }
 
             let editor = workspace
-                .update_in(&mut cx, |workspace, window, cx| {
+                .update_in(cx, |workspace, window, cx| {
                     workspace.open_path((tree_id, settings_relative_path), None, true, window, cx)
                 })?
                 .await?
@@ -1582,7 +1586,7 @@ fn open_local_file(
 
             editor
                 .downgrade()
-                .update(&mut cx, |editor, cx| {
+                .update(cx, |editor, cx| {
                     if let Some(buffer) = editor.buffer().read(cx).as_singleton() {
                         if buffer.read(cx).is_empty() {
                             buffer.update(cx, |buffer, cx| {
@@ -1612,7 +1616,7 @@ fn open_telemetry_log_file(
 ) {
     workspace.with_local_workspace(window, cx, move |workspace, window, cx| {
         let app_state = workspace.app_state().clone();
-        cx.spawn_in(window, |workspace, mut cx| async move {
+        cx.spawn_in(window, async move |workspace, cx| {
             async fn fetch_log_string(app_state: &Arc<AppState>) -> Option<String> {
                 let path = client::telemetry::Telemetry::log_file_path();
                 app_state.fs.load(&path).await.log_err()
@@ -1634,7 +1638,7 @@ fn open_telemetry_log_file(
             let content = format!("{}\n{}", header, log_suffix);
             let json = app_state.languages.language_for_name("JSON").await.log_err();
 
-            workspace.update_in(&mut cx, |workspace, window, cx| {
+            workspace.update_in( cx, |workspace, window, cx| {
                 let project = workspace.project().clone();
                 let buffer = project.update(cx, |project, cx| project.create_local_buffer(&content, json, cx));
                 let buffer = cx.new(|cx| {
@@ -1668,10 +1672,10 @@ fn open_bundled_file(
     cx: &mut Context<Workspace>,
 ) {
     let language = workspace.app_state().languages.language_for_name(language);
-    cx.spawn_in(window, |workspace, mut cx| async move {
+    cx.spawn_in(window, async move |workspace, cx| {
         let language = language.await.log_err();
         workspace
-            .update_in(&mut cx, |workspace, window, cx| {
+            .update_in(cx, |workspace, window, cx| {
                 workspace.with_local_workspace(window, cx, |workspace, window, cx| {
                     let project = workspace.project();
                     let buffer = project.update(cx, move |project, cx| {
@@ -1705,9 +1709,9 @@ fn open_settings_file(
     window: &mut Window,
     cx: &mut Context<Workspace>,
 ) {
-    cx.spawn_in(window, |workspace, mut cx| async move {
+    cx.spawn_in(window, async move |workspace, cx| {
         let (worktree_creation_task, settings_open_task) = workspace
-            .update_in(&mut cx, |workspace, window, cx| {
+            .update_in(cx, |workspace, window, cx| {
                 workspace.with_local_workspace(window, cx, move |workspace, window, cx| {
                     let worktree_creation_task = workspace.project().update(cx, |project, cx| {
                         // Set up a dedicated worktree for settings, since

crates/zed/src/zed/migrate.rs 🔗

@@ -121,9 +121,9 @@ impl ToolbarItemView for MigrationBanner {
             self.migration_type = Some(MigrationType::Keymap);
             let fs = <dyn Fs>::global(cx);
             let should_migrate = should_migrate_keymap(fs);
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 if let Ok(true) = should_migrate.await {
-                    this.update(&mut cx, |_, cx| {
+                    this.update(cx, |_, cx| {
                         cx.emit(ToolbarItemEvent::ChangeLocation(
                             ToolbarItemLocation::Secondary,
                         ));
@@ -137,9 +137,9 @@ impl ToolbarItemView for MigrationBanner {
             self.migration_type = Some(MigrationType::Settings);
             let fs = <dyn Fs>::global(cx);
             let should_migrate = should_migrate_settings(fs);
-            cx.spawn_in(window, |this, mut cx| async move {
+            cx.spawn_in(window, async move |this, cx| {
                 if let Ok(true) = should_migrate.await {
-                    this.update(&mut cx, |_, cx| {
+                    this.update(cx, |_, cx| {
                         cx.emit(ToolbarItemEvent::ChangeLocation(
                             ToolbarItemLocation::Secondary,
                         ));
@@ -213,16 +213,12 @@ impl Render for MigrationBanner {
                     let fs = <dyn Fs>::global(cx);
                     match migration_type {
                         Some(MigrationType::Keymap) => {
-                            cx.spawn(
-                                move |_| async move { write_keymap_migration(&fs).await.ok() },
-                            )
-                            .detach();
+                            cx.spawn(async move |_| write_keymap_migration(&fs).await.ok())
+                                .detach();
                         }
                         Some(MigrationType::Settings) => {
-                            cx.spawn(
-                                move |_| async move { write_settings_migration(&fs).await.ok() },
-                            )
-                            .detach();
+                            cx.spawn(async move |_| write_settings_migration(&fs).await.ok())
+                                .detach();
                         }
                         None => unreachable!(),
                     }

crates/zed/src/zed/open_listener.rs 🔗

@@ -251,7 +251,7 @@ pub async fn open_paths_with_positions(
 pub async fn handle_cli_connection(
     (mut requests, responses): (mpsc::Receiver<CliRequest>, IpcSender<CliResponse>),
     app_state: Arc<AppState>,
-    mut cx: AsyncApp,
+    cx: &mut AsyncApp,
 ) {
     if let Some(request) = requests.next().await {
         match request {
@@ -290,7 +290,7 @@ pub async fn handle_cli_connection(
                     wait,
                     app_state.clone(),
                     env,
-                    &mut cx,
+                    cx,
                 )
                 .await;
 
@@ -379,7 +379,7 @@ async fn open_workspaces(
                             .connection_options_for(ssh.host, ssh.port, ssh.user)
                     });
                     if let Ok(connection_options) = connection_options {
-                        cx.spawn(|mut cx| async move {
+                        cx.spawn(async move |mut cx| {
                             open_ssh_project(
                                 connection_options,
                                 ssh.paths.into_iter().map(PathBuf::from).collect(),

crates/zeta/src/onboarding_banner.rs 🔗

@@ -63,16 +63,22 @@ fn get_dismissed() -> bool {
 }
 
 fn persist_dismissed(cx: &mut App) {
-    cx.spawn(|_| {
+    cx.spawn(async |_| {
         let time = Utc::now().to_rfc3339();
-        db::kvp::KEY_VALUE_STORE.write_kvp(DISMISSED_AT_KEY.into(), time)
+        db::kvp::KEY_VALUE_STORE
+            .write_kvp(DISMISSED_AT_KEY.into(), time)
+            .await
     })
     .detach_and_log_err(cx);
 }
 
 pub(crate) fn clear_dismissed(cx: &mut App) {
-    cx.spawn(|_| db::kvp::KEY_VALUE_STORE.delete_kvp(DISMISSED_AT_KEY.into()))
-        .detach_and_log_err(cx);
+    cx.spawn(async |_| {
+        db::kvp::KEY_VALUE_STORE
+            .delete_kvp(DISMISSED_AT_KEY.into())
+            .await
+    })
+    .detach_and_log_err(cx);
 }
 
 impl Render for ZedPredictBanner {

crates/zeta/src/onboarding_modal.rs 🔗

@@ -85,11 +85,11 @@ impl ZedPredictModal {
             .update(cx, |this, cx| this.accept_terms_of_service(cx));
         let fs = self.fs.clone();
 
-        cx.spawn(|this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             task.await?;
 
             let mut data_collection_opted_in = false;
-            this.update(&mut cx, |this, _cx| {
+            this.update(cx, |this, _cx| {
                 data_collection_opted_in = this.data_collection_opted_in;
             })
             .ok();
@@ -116,7 +116,7 @@ impl ZedPredictModal {
                 }
             }
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 update_settings_file::<AllLanguageSettings>(this.fs.clone(), cx, move |file, _| {
                     file.features
                         .get_or_insert(Default::default())
@@ -138,7 +138,7 @@ impl ZedPredictModal {
         let client = self.client.clone();
         self.sign_in_status = SignInStatus::Waiting;
 
-        cx.spawn(move |this, mut cx| async move {
+        cx.spawn(async move |this, cx| {
             let result = client.authenticate_and_connect(true, &cx).await;
 
             let status = match result {
@@ -146,7 +146,7 @@ impl ZedPredictModal {
                 Err(_) => SignInStatus::Idle,
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 this.sign_in_status = status;
                 onboarding_event!("Signed In");
                 cx.notify()

crates/zeta/src/zeta.rs 🔗

@@ -262,7 +262,7 @@ impl Zeta {
                 |this, _listener, _event, cx| {
                     let client = this.client.clone();
                     let llm_token = this.llm_token.clone();
-                    cx.spawn(|_this, _cx| async move {
+                    cx.spawn(async move |_this, _cx| {
                         llm_token.refresh(&client).await?;
                         anyhow::Ok(())
                     })
@@ -405,7 +405,7 @@ impl Zeta {
             None
         };
 
-        cx.spawn(|_, cx| async move {
+        cx.spawn(async move |_, cx| {
             let request_sent_at = Instant::now();
 
             struct BackgroundValues {
@@ -666,12 +666,12 @@ and then another
             ),
         ];
 
-        cx.spawn(|zeta, mut cx| async move {
+        cx.spawn(async move |zeta, cx| {
             for task in completion_tasks {
                 task.await.unwrap();
             }
 
-            zeta.update(&mut cx, |zeta, _cx| {
+            zeta.update(cx, |zeta, _cx| {
                 zeta.shown_completions.get_mut(2).unwrap().edits = Arc::new([]);
                 zeta.shown_completions.get_mut(3).unwrap().edits = Arc::new([]);
             })
@@ -806,7 +806,7 @@ and then another
         let snapshot = snapshot.clone();
         let request_id = prediction_response.request_id;
         let output_excerpt = prediction_response.output_excerpt;
-        cx.spawn(|cx| async move {
+        cx.spawn(async move |cx| {
             let output_excerpt: Arc<str> = output_excerpt.into();
 
             let edits: Arc<[(Range<Anchor>, String)]> = cx
@@ -819,7 +819,7 @@ and then another
                 .await?
                 .into();
 
-            let Some((edits, snapshot, edit_preview)) = buffer.read_with(&cx, {
+            let Some((edits, snapshot, edit_preview)) = buffer.read_with(cx, {
                 let edits = edits.clone();
                 |buffer, cx| {
                     let new_snapshot = buffer.snapshot();
@@ -1457,14 +1457,14 @@ impl inline_completion::EditPredictionProvider for ZetaInlineCompletionProvider
         let can_collect_data = self.provider_data_collection.can_collect_data(cx);
         let last_request_timestamp = self.last_request_timestamp;
 
-        let task = cx.spawn(|this, mut cx| async move {
+        let task = cx.spawn(async move |this, cx| {
             if let Some(timeout) = (last_request_timestamp + Self::THROTTLE_TIMEOUT)
                 .checked_duration_since(Instant::now())
             {
                 cx.background_executor().timer(timeout).await;
             }
 
-            let completion_request = this.update(&mut cx, |this, cx| {
+            let completion_request = this.update(cx, |this, cx| {
                 this.last_request_timestamp = Instant::now();
                 this.zeta.update(cx, |zeta, cx| {
                     zeta.request_completion(
@@ -1494,7 +1494,7 @@ impl inline_completion::EditPredictionProvider for ZetaInlineCompletionProvider
                 .log_err()
                 .flatten()
             else {
-                this.update(&mut cx, |this, cx| {
+                this.update(cx, |this, cx| {
                     if this.pending_completions[0].id == pending_completion_id {
                         this.pending_completions.remove(0);
                     } else {
@@ -1507,7 +1507,7 @@ impl inline_completion::EditPredictionProvider for ZetaInlineCompletionProvider
                 return;
             };
 
-            this.update(&mut cx, |this, cx| {
+            this.update(cx, |this, cx| {
                 if this.pending_completions[0].id == pending_completion_id {
                     this.pending_completions.remove(0);
                 } else {