diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index 5fd1f27631..dbe3596a43 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/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) diff --git a/crates/askpass/src/askpass.rs b/crates/askpass/src/askpass.rs index cf0349759e..94e5f6cc0b 100644 --- a/crates/askpass/src/askpass.rs +++ b/crates/askpass/src/askpass.rs @@ -34,9 +34,9 @@ impl AskPassDelegate { password_prompt: impl Fn(String, oneshot::Sender, &mut AsyncApp) + Send + Sync + 'static, ) -> Self { let (tx, mut rx) = mpsc::unbounded::<(String, oneshot::Sender)>(); - 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 } diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs index 63d715d8a7..828520fe41 100644 --- a/crates/assistant/src/assistant.rs +++ b/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::())? .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?; diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 8d5d703a13..29833d1229 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -98,16 +98,16 @@ impl AssistantPanel { prompt_builder: Arc, cx: AsyncWindowContext, ) -> Task>> { - 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::(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::(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, diff --git a/crates/assistant/src/inline_assistant.rs b/crates/assistant/src/inline_assistant.rs index 79cf97ff88..aa67347c1c 100644 --- a/crates/assistant/src/inline_assistant.rs +++ b/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) { 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> = - 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(); + 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> = + 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; + 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); + 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 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), - ); + 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?; + 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 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(); } - - 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; - } + 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?; - - 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 - } - }) - .collect::>(); - - 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(); - })?; - } + 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?; - // 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(()) + }; - anyhow::Ok(()) - }; + let result = diff.await; - let result = generate.await; - let elapsed_time = start_time.elapsed().as_secs_f64(); + 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, + ); - 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; + 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::>(); + + 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(); } @@ -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> { 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::(cx) .context("assistant panel was released") diff --git a/crates/assistant/src/terminal_inline_assistant.rs b/crates/assistant/src/terminal_inline_assistant.rs index 1acbd5f414..b3132d44f2 100644 --- a/crates/assistant/src/terminal_inline_assistant.rs +++ b/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 { diff --git a/crates/assistant2/src/active_thread.rs b/crates/assistant2/src/active_thread.rs index a9797166f3..570ae756a3 100644 --- a/crates/assistant2/src/active_thread.rs +++ b/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) { 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)) }) diff --git a/crates/assistant2/src/assistant_panel.rs b/crates/assistant2/src/assistant_panel.rs index 805e1d423b..a963a0f538 100644 --- a/crates/assistant2/src/assistant_panel.rs +++ b/crates/assistant2/src/assistant_panel.rs @@ -110,16 +110,16 @@ impl AssistantPanel { prompt_builder: Arc, cx: AsyncWindowContext, ) -> Task>> { - 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 diff --git a/crates/assistant2/src/buffer_codegen.rs b/crates/assistant2/src/buffer_codegen.rs index c9ddc2d4e5..230670b260 100644 --- a/crates/assistant2/src/buffer_codegen.rs +++ b/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> = - 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(); + 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> = + 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; + 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); + 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 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), - ); + 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?; + 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 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(); } - - 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; - } + 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?; - - 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 - } - }) - .collect::>(); - - 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(); - })?; - } + 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?; - // 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(()) + }; - anyhow::Ok(()) - }; + let result = diff.await; - let result = generate.await; - let elapsed_time = start_time.elapsed().as_secs_f64(); + 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, + ); - 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; + 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::>(); + + 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(); diff --git a/crates/assistant2/src/context_picker.rs b/crates/assistant2/src/context_picker.rs index b33f082857..013fe717b2 100644 --- a/crates/assistant2/src/context_picker.rs +++ b/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()) }) } diff --git a/crates/assistant2/src/context_picker/fetch_context_picker.rs b/crates/assistant2/src/context_picker/fetch_context_picker.rs index 52c682b647..35e92b5fe3 100644 --- a/crates/assistant2/src/context_picker/fetch_context_picker.rs +++ b/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| { diff --git a/crates/assistant2/src/context_picker/file_context_picker.rs b/crates/assistant2/src/context_picker/file_context_picker.rs index 6b4858434e..f856f06e51 100644 --- a/crates/assistant2/src/context_picker/file_context_picker.rs +++ b/crates/assistant2/src/context_picker/file_context_picker.rs @@ -206,11 +206,11 @@ impl PickerDelegate for FileContextPickerDelegate { let search_task = self.search(query, Arc::::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), }), diff --git a/crates/assistant2/src/context_picker/thread_context_picker.rs b/crates/assistant2/src/context_picker/thread_context_picker.rs index 914745e224..82925492fb 100644 --- a/crates/assistant2/src/context_picker/thread_context_picker.rs +++ b/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)) diff --git a/crates/assistant2/src/context_store.rs b/crates/assistant2/src/context_store.rs index f060bb0a40..c74658a678 100644 --- a/crates/assistant2/src/context_store.rs +++ b/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, cx: &mut Context, ) -> Task> { - 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, diff --git a/crates/assistant2/src/context_strip.rs b/crates/assistant2/src/context_strip.rs index 60381af06d..e1c5ecfacb 100644 --- a/crates/assistant2/src/context_strip.rs +++ b/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())?; } } } diff --git a/crates/assistant2/src/inline_assistant.rs b/crates/assistant2/src/inline_assistant.rs index fd42ed1a24..9952540d6b 100644 --- a/crates/assistant2/src/inline_assistant.rs +++ b/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); diff --git a/crates/assistant2/src/message_editor.rs b/crates/assistant2/src/message_editor.rs index 9917982457..a095e8bb3e 100644 --- a/crates/assistant2/src/message_editor.rs +++ b/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::>(); 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 { diff --git a/crates/assistant2/src/terminal_codegen.rs b/crates/assistant2/src/terminal_codegen.rs index 106eac6171..850beda229 100644 --- a/crates/assistant2/src/terminal_codegen.rs +++ b/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 { diff --git a/crates/assistant2/src/thread.rs b/crates/assistant2/src/thread.rs index 9e97a9d7c4..a89dba5660 100644 --- a/crates/assistant2/src/thread.rs +++ b/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) -> Task> { 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>, cx: &mut Context, ) { - 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>, cx: &mut Context, ) { - 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, cx: &App) -> Task { - 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(); diff --git a/crates/assistant2/src/thread_store.rs b/crates/assistant2/src/thread_store.rs index 623bfac2ac..7468cc1f36 100644 --- a/crates/assistant2/src/thread_store.rs +++ b/crates/assistant2/src/thread_store.rs @@ -106,14 +106,14 @@ impl ThreadStore { ) -> Task>> { 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) -> Task> { 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) -> Task> { 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::>(); - this.update(&mut cx, |this, _cx| { + this.update(cx, |this, _cx| { this.context_server_tool_ids.insert(server_id, tool_ids); }) .log_err(); diff --git a/crates/assistant_context_editor/src/context.rs b/crates/assistant_context_editor/src/context.rs index 4120f5b22e..ef15afd05c 100644 --- a/crates/assistant_context_editor/src/context.rs +++ b/crates/assistant_context_editor/src/context.rs @@ -1144,9 +1144,9 @@ impl AssistantContext { fn set_language(&mut self, cx: &mut Context) { 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::() { 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(()) diff --git a/crates/assistant_context_editor/src/context_editor.rs b/crates/assistant_context_editor/src/context_editor.rs index 4f74da00a8..bdc5a51a92 100644 --- a/crates/assistant_context_editor/src/context_editor.rs +++ b/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, 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, 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::>(); - 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( diff --git a/crates/assistant_context_editor/src/context_history.rs b/crates/assistant_context_editor/src/context_history.rs index 2401f6d70b..83df49e16f 100644 --- a/crates/assistant_context_editor/src/context_history.rs +++ b/crates/assistant_context_editor/src/context_history.rs @@ -164,9 +164,9 @@ impl PickerDelegate for SavedContextPickerDelegate { cx: &mut Context>, ) -> 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() diff --git a/crates/assistant_context_editor/src/context_store.rs b/crates/assistant_context_editor/src/context_store.rs index 557b6d3e6e..86e0b48743 100644 --- a/crates/assistant_context_editor/src/context_store.rs +++ b/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::>>() }) .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> { 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::>>() }) .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) -> Task> { 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::>(); - this.update(&mut cx, |this, _cx| { + this.update( cx, |this, _cx| { this.context_server_slash_command_ids .insert(server_id.clone(), slash_command_ids); }) diff --git a/crates/assistant_context_editor/src/slash_command.rs b/crates/assistant_context_editor/src/slash_command.rs index 8b7a745e56..d5139c8f37 100644 --- a/crates/assistant_context_editor/src/slash_command.rs +++ b/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, diff --git a/crates/assistant_context_editor/src/slash_command_picker.rs b/crates/assistant_context_editor/src/slash_command_picker.rs index 7c762ff45b..6666317639 100644 --- a/crates/assistant_context_editor/src/slash_command_picker.rs +++ b/crates/assistant_context_editor/src/slash_command_picker.rs @@ -100,7 +100,7 @@ impl PickerDelegate for SlashCommandDelegate { cx: &mut Context>, ) -> 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(); diff --git a/crates/assistant_eval/src/eval.rs b/crates/assistant_eval/src/eval.rs index 98e72ec6b5..5ce7c02d8e 100644 --- a/crates/assistant_eval/src/eval.rs +++ b/crates/assistant_eval/src/eval.rs @@ -63,14 +63,14 @@ impl Eval { model: Arc, cx: &mut App, ) -> Task> { - 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 { diff --git a/crates/assistant_eval/src/headless_assistant.rs b/crates/assistant_eval/src/headless_assistant.rs index ea0eaf33c8..d26b03bee2 100644 --- a/crates/assistant_eval/src/headless_assistant.rs +++ b/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, request: LanguageModelRequest, - cx: AsyncApp, + cx: &mut AsyncApp, ) -> anyhow::Result { match model.stream_completion_text(request, &cx).await { Ok(mut stream) => { diff --git a/crates/assistant_eval/src/judge.rs b/crates/assistant_eval/src/judge.rs index 4b3e6f26a4..5a669362ed 100644 --- a/crates/assistant_eval/src/judge.rs +++ b/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) } } diff --git a/crates/assistant_eval/src/main.rs b/crates/assistant_eval/src/main.rs index 2bde8b074f..786e858f6a 100644 --- a/crates/assistant_eval/src/main.rs +++ b/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() diff --git a/crates/assistant_slash_commands/src/auto_command.rs b/crates/assistant_slash_commands/src/auto_command.rs index 967666aaa4..1db397557e 100644 --- a/crates/assistant_slash_commands/src/auto_command.rs +++ b/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 diff --git a/crates/assistant_slash_commands/src/diagnostics_command.rs b/crates/assistant_slash_commands/src/diagnostics_command.rs index 7152a91a61..716fcbcd1d 100644 --- a/crates/assistant_slash_commands/src/diagnostics_command.rs +++ b/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() { diff --git a/crates/assistant_slash_commands/src/file_command.rs b/crates/assistant_slash_commands/src/file_command.rs index 051a0f289f..c26df24556 100644 --- a/crates/assistant_slash_commands/src/file_command.rs +++ b/crates/assistant_slash_commands/src/file_command.rs @@ -241,7 +241,7 @@ fn collect_files( .collect::>(); 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> = 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), diff --git a/crates/assistant_slash_commands/src/project_command.rs b/crates/assistant_slash_commands/src/project_command.rs index 62be5049fc..584db58b59 100644 --- a/crates/assistant_slash_commands/src/project_command.rs +++ b/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?; diff --git a/crates/assistant_slash_commands/src/search_command.rs b/crates/assistant_slash_commands/src/search_command.rs index 8005de0bc9..270b0b7424 100644 --- a/crates/assistant_slash_commands/src/search_command.rs +++ b/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?; diff --git a/crates/assistant_slash_commands/src/tab_command.rs b/crates/assistant_slash_commands/src/tab_command.rs index 111ea05e4c..c4953aec30 100644 --- a/crates/assistant_slash_commands/src/tab_command.rs +++ b/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, 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); diff --git a/crates/assistant_tools/src/bash_tool.rs b/crates/assistant_tools/src/bash_tool.rs index 5f6d957508..6befc4dbae 100644 --- a/crates/assistant_tools/src/bash_tool.rs +++ b/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); diff --git a/crates/assistant_tools/src/diagnostics_tool.rs b/crates/assistant_tools/src/diagnostics_tool.rs index e9d36cc016..62d77b7273 100644 --- a/crates/assistant_tools/src/diagnostics_tool.rs +++ b/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]; diff --git a/crates/assistant_tools/src/edit_files_tool.rs b/crates/assistant_tools/src/edit_files_tool.rs index 20bc177fdf..3c4f560b93 100644 --- a/crates/assistant_tools/src/edit_files_tool.rs +++ b/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 }) } diff --git a/crates/assistant_tools/src/read_file_tool.rs b/crates/assistant_tools/src/read_file_tool.rs index 59c6b55071..13cd6a9eea 100644 --- a/crates/assistant_tools/src/read_file_tool.rs +++ b/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); })?; diff --git a/crates/assistant_tools/src/regex_search_tool.rs b/crates/assistant_tools/src/regex_search_tool.rs index 54f680d1f2..2849870846 100644 --- a/crates/assistant_tools/src/regex_search_tool.rs +++ b/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 diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index c1dbf2f686..11a699b0b6 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/crates/auto_update/src/auto_update.rs @@ -252,11 +252,9 @@ impl AutoUpdater { } pub fn start_polling(&self, cx: &mut Context) -> Task> { - 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); diff --git a/crates/auto_update_ui/src/auto_update_ui.rs b/crates/auto_update_ui/src/auto_update_ui.rs index 0ef89da85e..61aebaf8ed 100644 --- a/crates/auto_update_ui/src/auto_update_ui.rs +++ b/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| { diff --git a/crates/buffer_diff/src/buffer_diff.rs b/crates/buffer_diff/src/buffer_diff.rs index 62f46e4c19..0ae9095021 100644 --- a/crates/buffer_diff/src/buffer_diff.rs +++ b/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(); diff --git a/crates/call/src/cross_platform/mod.rs b/crates/call/src/cross_platform/mod.rs index 429e7ee288..2704daf92b 100644 --- a/crates/call/src/cross_platform/mod.rs +++ b/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) }) } diff --git a/crates/call/src/cross_platform/room.rs b/crates/call/src/cross_platform/room.rs index 250e33b027..a06460094a 100644 --- a/crates/call/src/cross_platform/room.rs +++ b/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, cx: &mut App, ) -> Task>> { - 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, client: Arc, - 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() diff --git a/crates/call/src/macos/mod.rs b/crates/call/src/macos/mod.rs index d7aef97327..49ff6f3ef6 100644 --- a/crates/call/src/macos/mod.rs +++ b/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) }) } diff --git a/crates/call/src/macos/room.rs b/crates/call/src/macos/room.rs index 6c9dd1ba50..0fa916e1c8 100644 --- a/crates/call/src/macos/room.rs +++ b/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, cx: &mut App, ) -> Task>> { - 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, user_store: Entity, - cx: AsyncApp, + cx: &mut AsyncApp, ) -> Result> { Self::from_join_response( client @@ -292,7 +295,7 @@ impl Room { room_id: u64, client: Arc, user_store: Entity, - cx: AsyncApp, + cx: &mut AsyncApp, ) -> Result> { Self::from_join_response( client.request(proto::JoinRoom { id: room_id }).await?, @@ -333,7 +336,7 @@ impl Room { response: proto::JoinRoomResponse, client: Arc, user_store: Entity, - mut cx: AsyncApp, + cx: &mut AsyncApp, ) -> Result> { 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, client: Arc, - 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() diff --git a/crates/channel/src/channel_buffer.rs b/crates/channel/src/channel_buffer.rs index 31bac60210..527e2d517f 100644 --- a/crates/channel/src/channel_buffer.rs +++ b/crates/channel/src/channel_buffer.rs @@ -47,7 +47,7 @@ impl ChannelBuffer { client: Arc, user_store: Entity, channel_store: Entity, - mut cx: AsyncApp, + cx: &mut AsyncApp, ) -> Result> { 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; diff --git a/crates/channel/src/channel_chat.rs b/crates/channel/src/channel_chat.rs index e16e27ac36..2b127a71eb 100644 --- a/crates/channel/src/channel_chat.rs +++ b/crates/channel/src/channel_chat.rs @@ -106,7 +106,7 @@ impl ChannelChat { channel_store: Entity, user_store: Entity, client: Arc, - mut cx: AsyncApp, + cx: &mut AsyncApp, ) -> Result> { 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::>() })?; @@ -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(); } diff --git a/crates/channel/src/channel_store.rs b/crates/channel/src/channel_store.rs index 2e12874892..01b78ff527 100644 --- a/crates/channel/src/channel_store.rs +++ b/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( + fn open_channel_resource( &mut self, channel_id: ChannelId, get_map: fn(&mut Self) -> &mut HashMap>, @@ -458,8 +459,7 @@ impl ChannelStore { cx: &mut Context, ) -> Task>> where - F: 'static + FnOnce(Arc, AsyncApp) -> Fut, - Fut: Future>>, + F: AsyncFnOnce(Arc, &mut AsyncApp) -> Result> + '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> { 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, ) -> Task> { 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, ) -> Task> { 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> { 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>> { 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 diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index e6870bf2f8..2fbc1bab61 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -144,9 +144,9 @@ pub fn init(client: &Arc, 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, 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, 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, cx: &AsyncApp) -> Task> { 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::(); 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(); diff --git a/crates/client/src/test.rs b/crates/client/src/test.rs index 83781248ad..2f23d43ae3 100644 --- a/crates/client/src/test.rs +++ b/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 { diff --git a/crates/client/src/user.rs b/crates/client/src/user.rs index 9a6cbc5542..2fb0097657 100644 --- a/crates/client/src/user.rs +++ b/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::::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, ) -> Task> { 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, ) -> Task>>> { 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); diff --git a/crates/collab/src/tests/channel_buffer_tests.rs b/crates/collab/src/tests/channel_buffer_tests.rs index c253acf54b..6286670d3d 100644 --- a/crates/collab/src/tests/channel_buffer_tests.rs +++ b/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; diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index fda8f111a7..5574d52d31 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/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), diff --git a/crates/collab/src/tests/test_server.rs b/crates/collab/src/tests/test_server.rs index fc33ccea22..11a5d0530d 100644 --- a/crates/collab/src/tests/test_server.rs +++ b/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" diff --git a/crates/collab_ui/src/channel_view.rs b/crates/collab_ui/src/channel_view.rs index 46e9d04967..ca910e2f9b 100644 --- a/crates/collab_ui/src/channel_view.rs +++ b/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>> { 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 { diff --git a/crates/collab_ui/src/chat_panel.rs b/crates/collab_ui/src/chat_panel.rs index 813770748d..c480fe55a6 100644 --- a/crates/collab_ui/src/chat_panel.rs +++ b/crates/collab_ui/src/chat_panel.rs @@ -199,7 +199,7 @@ impl ChatPanel { workspace: WeakEntity, cx: AsyncWindowContext, ) -> Task>> { - 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(); }) diff --git a/crates/collab_ui/src/chat_panel/message_editor.rs b/crates/collab_ui/src/chat_panel/message_editor.rs index 760f4119c7..95025c65ca 100644 --- a/crates/collab_ui/src/chat_panel/message_editor.rs +++ b/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, 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(); diff --git a/crates/collab_ui/src/collab_panel.rs b/crates/collab_ui/src/collab_panel.rs index 041e36be98..382fd922b0 100644 --- a/crates/collab_ui/src/collab_panel.rs +++ b/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() })), diff --git a/crates/collab_ui/src/collab_panel/channel_modal.rs b/crates/collab_ui/src/collab_panel/channel_modal.rs index 5feb046607..f2949305ec 100644 --- a/crates/collab_ui/src/collab_panel/channel_modal.rs +++ b/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, diff --git a/crates/collab_ui/src/collab_panel/contact_finder.rs b/crates/collab_ui/src/collab_panel/contact_finder.rs index 64b2f6f5b2..325f749c09 100644 --- a/crates/collab_ui/src/collab_panel/contact_finder.rs +++ b/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(); })?; diff --git a/crates/collab_ui/src/notification_panel.rs b/crates/collab_ui/src/notification_panel.rs index bfc8197408..a45a0c0989 100644 --- a/crates/collab_ui/src/notification_panel.rs +++ b/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, cx: AsyncWindowContext, ) -> Task>> { - 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(¬ification_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() diff --git a/crates/collab_ui/src/notifications/incoming_call_notification.rs b/crates/collab_ui/src/notifications/incoming_call_notification.rs index 1ee4fd480f..a3b40f0232 100644 --- a/crates/collab_ui/src/notifications/incoming_call_notification.rs +++ b/crates/collab_ui/src/notifications/incoming_call_notification.rs @@ -12,12 +12,12 @@ use workspace::AppState; pub fn init(app_state: &Arc, 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> = 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| { diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index cdf1d68ac8..0a29aaedc9 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/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) diff --git a/crates/component_preview/src/component_preview.rs b/crates/component_preview/src/component_preview.rs index e913f80177..b5e374ec01 100644 --- a/crates/component_preview/src/component_preview.rs +++ b/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(); diff --git a/crates/context_server/src/client.rs b/crates/context_server/src/client.rs index 83517fc238..de035dac3d 100644 --- a/crates/context_server/src/client.rs +++ b/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, notification_handlers: Arc>>, response_handlers: Arc>>>, - cx: AsyncApp, + cx: &mut AsyncApp, ) -> anyhow::Result<()> { let mut receiver = transport.receive(); diff --git a/crates/context_server/src/extension_context_server.rs b/crates/context_server/src/extension_context_server.rs index efbbc6d594..96d1ccaf53 100644 --- a/crates/context_server/src/extension_context_server.rs +++ b/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) diff --git a/crates/context_server/src/manager.rs b/crates/context_server/src/manager.rs index 1441548b04..c698176958 100644 --- a/crates/context_server/src/manager.rs +++ b/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, ) -> Task> { 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, mut cx: AsyncApp) -> Result<()> { + async fn maintain_servers(this: WeakEntity, 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 }))?; } } diff --git a/crates/context_server/src/transport/stdio_transport.rs b/crates/context_server/src/transport/stdio_transport.rs index cdfe58a4bd..56d0240fa5 100644 --- a/crates/context_server/src/transport/stdio_transport.rs +++ b/crates/context_server/src/transport/stdio_transport.rs @@ -47,13 +47,13 @@ impl StdioTransport { let (stdout_sender, stdout_receiver) = channel::unbounded::(); let (stderr_sender, stderr_receiver) = channel::unbounded::(); - 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 { diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index 8896aa5ea2..d1b686ed1e 100644 --- a/crates/copilot/src/copilot.rs +++ b/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>, this: WeakEntity, 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::( @@ -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 diff --git a/crates/copilot/src/copilot_chat.rs b/crates/copilot/src/copilot_chat.rs index bccdfd9cc9..3c3c193e78 100644 --- a/crates/copilot/src/copilot_chat.rs +++ b/crates/copilot/src/copilot_chat.rs @@ -241,7 +241,7 @@ impl CopilotChat { let config_paths: HashSet = 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(), diff --git a/crates/copilot/src/copilot_completion_provider.rs b/crates/copilot/src/copilot_completion_provider.rs index 95640f8527..8c5b1b3bf1 100644 --- a/crates/copilot/src/copilot_completion_provider.rs +++ b/crates/copilot/src/copilot_completion_provider.rs @@ -83,7 +83,7 @@ impl EditPredictionProvider for CopilotCompletionProvider { cx: &mut Context, ) { 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( diff --git a/crates/copilot/src/sign_in.rs b/crates/copilot/src/sign_in.rs index 3ae6078f1d..4afff98c4f 100644 --- a/crates/copilot/src/sign_in.rs +++ b/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::(), diff --git a/crates/dap/src/transport.rs b/crates/dap/src/transport.rs index d960503b55..9ae462fdc0 100644 --- a/crates/dap/src/transport.rs +++ b/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(), diff --git a/crates/debugger_tools/src/dap_log.rs b/crates/debugger_tools/src/dap_log.rs index 0cf1b2140c..5594588085 100644 --- a/crates/debugger_tools/src/dap_log.rs +++ b/crates/debugger_tools/src/dap_log.rs @@ -103,10 +103,10 @@ impl DebugAdapterState { impl LogStore { fn new(cx: &Context) -> 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); }) } diff --git a/crates/debugger_ui/src/attach_modal.rs b/crates/debugger_ui/src/attach_modal.rs index b39c59f4cf..4756b0d693 100644 --- a/crates/debugger_ui/src/attach_modal.rs +++ b/crates/debugger_ui/src/attach_modal.rs @@ -114,9 +114,9 @@ impl PickerDelegate for AttachModalDelegate { _window: &mut Window, cx: &mut Context>, ) -> 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; diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs index 5d43327548..4700ae2ac7 100644 --- a/crates/debugger_ui/src/debugger_panel.rs +++ b/crates/debugger_ui/src/debugger_panel.rs @@ -150,8 +150,8 @@ impl DebugPanel { workspace: WeakEntity, cx: AsyncWindowContext, ) -> Task>> { - 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 diff --git a/crates/debugger_ui/src/session/running/console.rs b/crates/debugger_ui/src/session/running/console.rs index 6fc59bd49c..8260c5e6a9 100644 --- a/crates/debugger_ui/src/session/running/console.rs +++ b/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) -> 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, diff --git a/crates/debugger_ui/src/session/running/module_list.rs b/crates/debugger_ui/src/session/running/module_list.rs index e0e8f717a2..0b0c43b0d7 100644 --- a/crates/debugger_ui/src/session/running/module_list.rs +++ b/crates/debugger_ui/src/session/running/module_list.rs @@ -60,9 +60,9 @@ impl ModuleList { } fn open_module(&mut self, path: Arc, window: &mut Window, cx: &mut Context) { - 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") diff --git a/crates/debugger_ui/src/session/running/stack_frame_list.rs b/crates/debugger_ui/src/session/running/stack_frame_list.rs index 728f3e3de2..df0ea9eaaa 100644 --- a/crates/debugger_ui/src/session/running/stack_frame_list.rs +++ b/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(); diff --git a/crates/debugger_ui/src/session/starting.rs b/crates/debugger_ui/src/session/starting.rs index 652e3dd7b2..dfbb7bb947 100644 --- a/crates/debugger_ui/src/session/starting.rs +++ b/crates/debugger_ui/src/session/starting.rs @@ -29,10 +29,10 @@ impl StartingState { task: Task>>, cx: &mut Context, ) -> 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 { diff --git a/crates/debugger_ui/src/tests.rs b/crates/debugger_ui/src/tests.rs index 2f1be7cd2e..441f5c3da8 100644 --- a/crates/debugger_ui/src/tests.rs +++ b/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"); diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 99b2dc91a1..090ceacdb8 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/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> { - 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, max_row_count: u32, snapshot: BufferSnapshot, - cx: AsyncApp, + cx: &mut AsyncApp, ) -> Option> { let input_row_count = input_range.end.row - input_range.start.row; if input_row_count > max_row_count { diff --git a/crates/diagnostics/src/items.rs b/crates/diagnostics/src/items.rs index 017adc5017..ab77ae2f07 100644 --- a/crates/diagnostics/src/items.rs +++ b/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(); }) diff --git a/crates/editor/src/blink_manager.rs b/crates/editor/src/blink_manager.rs index 1dafe5d75c..5de1e2b6b9 100644 --- a/crates/editor/src/blink_manager.rs +++ b/crates/editor/src/blink_manager.rs @@ -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(); } }) diff --git a/crates/editor/src/clangd_ext.rs b/crates/editor/src/clangd_ext.rs index 4d4ef2a5ed..2e4b539b16 100644 --- a/crates/editor/src/clangd_ext.rs +++ b/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(|| { diff --git a/crates/editor/src/code_context_menus.rs b/crates/editor/src/code_context_menus.rs index d59514c169..49a93a92ec 100644 --- a/crates/editor/src/code_context_menus.rs +++ b/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(); diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index 8396c05b90..2c6b0ce378 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/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 diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 65e0e849bd..1ad7247b2e 100644 --- a/crates/editor/src/editor.rs +++ b/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, transaction: ProjectTransaction, title: String, - mut cx: AsyncWindowContext, + cx: &mut AsyncWindowContext, ) -> Result<()> { let mut entries = transaction.0.into_iter().collect::>(); 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::(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::(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::(cx); if !matches.is_empty() { editor.highlight_background::( @@ -5342,9 +5343,9 @@ impl Editor { fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context) { 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> { 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, ) { 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::(), - message, - ), - cx, - ) - }) - .ok(); - } + workspace.show_toast( + Toast::new( + NotificationId::unique::(), + 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::(), - message, - ), - cx, - ) - }) - .ok(); - } + workspace.show_toast( + Toast::new( + NotificationId::unique::(), + 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 { 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) { diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 735489dfcd..85f1e2f14e 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -9312,6 +9312,7 @@ async fn test_word_completion(cx: &mut TestAppContext) { .server .on_request::(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() diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 17e765db91..06d2204165 100644 --- a/crates/editor/src/element.rs +++ b/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; diff --git a/crates/editor/src/git/blame.rs b/crates/editor/src/git/blame.rs index 38db2d2dc1..fd4560c3ca 100644 --- a/crates/editor/src/git/blame.rs +++ b/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.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); }) }) diff --git a/crates/editor/src/hover_links.rs b/crates/editor/src/hover_links.rs index cfb282e46a..16dfcaa21e 100644 --- a/crates/editor/src/hover_links.rs +++ b/crates/editor/src/hover_links.rs @@ -167,10 +167,10 @@ impl Editor { cx: &mut Context, ) { 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::(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); diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 465cd307c7..65b1d160e6 100644 --- a/crates/editor/src/hover_popover.rs +++ b/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::(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::(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, diff --git a/crates/editor/src/indent_guides.rs b/crates/editor/src/indent_guides.rs index 7068a94ac4..a17c0669b6 100644 --- a/crates/editor/src/indent_guides.rs +++ b/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; } } diff --git a/crates/editor/src/inlay_hint_cache.rs b/crates/editor/src/inlay_hint_cache.rs index d5c14b0870..4b5c4c5100 100644 --- a/crates/editor/src/inlay_hint_cache.rs +++ b/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, cx: &mut Context, ) -> 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, ) -> Task> { - 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, diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 33ecf3b858..200556b85e 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -87,7 +87,7 @@ impl FollowableItem for Editor { .collect::>>() }); - 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> { 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::>(); - 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> { - 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::().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::().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(); diff --git a/crates/editor/src/jsx_tag_auto_close.rs b/crates/editor/src/jsx_tag_auto_close.rs index 990e94630f..d41f70f18e 100644 --- a/crates/editor/src/jsx_tag_auto_close.rs +++ b/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<()> { //
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::>(); - 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); }); diff --git a/crates/editor/src/linked_editing_ranges.rs b/crates/editor/src/linked_editing_ranges.rs index f4cc84c2a0..90617d52f2 100644 --- a/crates/editor/src/linked_editing_ranges.rs +++ b/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::(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; diff --git a/crates/editor/src/proposed_changes_editor.rs b/crates/editor/src/proposed_changes_editor.rs index 7aa803cf35..bb6ac55bdf 100644 --- a/crates/editor/src/proposed_changes_editor.rs +++ b/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| { diff --git a/crates/editor/src/rust_analyzer_ext.rs b/crates/editor/src/rust_analyzer_ext.rs index 73e1093ae4..c577dcc2a8 100644 --- a/crates/editor/src/rust_analyzer_ext.rs +++ b/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 { diff --git a/crates/editor/src/scroll.rs b/crates/editor/src/scroll.rs index 0ba1fde0ab..f463777b7e 100644 --- a/crates/editor/src/scroll.rs +++ b/crates/editor/src/scroll.rs @@ -341,12 +341,12 @@ impl ScrollManager { } if cx.default_global::().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() diff --git a/crates/editor/src/scroll/actions.rs b/crates/editor/src/scroll/actions.rs index a9a187267a..9e829b196f 100644 --- a/crates/editor/src/scroll/actions.rs +++ b/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(); diff --git a/crates/editor/src/signature_help.rs b/crates/editor/src/signature_help.rs index 1e1dd15aa9..51e85582e3 100644 --- a/crates/editor/src/signature_help.rs +++ b/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 diff --git a/crates/evals/src/eval.rs b/crates/evals/src/eval.rs index fd60221ba9..eba827ff79 100644 --- a/crates/evals/src/eval.rs +++ b/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); } diff --git a/crates/extension_host/src/extension_host.rs b/crates/extension_host/src/extension_host.rs index a317360614..a0fa34b38b 100644 --- a/crates/extension_host/src/extension_host.rs +++ b/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::>(); - 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) { 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>> { 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 { diff --git a/crates/extension_host/src/headless_host.rs b/crates/extension_host/src/headless_host.rs index 19f87d0d25..3aaf610b85 100644 --- a/crates/extension_host/src/headless_host.rs +++ b/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 }) } diff --git a/crates/extension_host/src/wasm_host.rs b/crates/extension_host/src/wasm_host.rs index 3c22115c05..0d9c2d053f 100644 --- a/crates/extension_host/src/wasm_host.rs +++ b/crates/extension_host/src/wasm_host.rs @@ -334,9 +334,9 @@ impl WasmHost { cx: &mut App, ) -> Arc { let (tx, mut rx) = mpsc::unbounded::(); - 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 { diff --git a/crates/extensions_ui/src/extension_version_selector.rs b/crates/extensions_ui/src/extension_version_selector.rs index 8a3bc5aca6..8e9b85c860 100644 --- a/crates/extensions_ui/src/extension_version_selector.rs +++ b/crates/extensions_ui/src/extension_version_selector.rs @@ -129,7 +129,7 @@ impl PickerDelegate for ExtensionVersionSelectorDelegate { }) .collect::>(); - 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 diff --git a/crates/extensions_ui/src/extensions_ui.rs b/crates/extensions_ui/src/extensions_ui.rs index afe1ce693c..9f3197fb08 100644 --- a/crates/extensions_ui/src/extensions_ui.rs +++ b/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) { - 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(); diff --git a/crates/feature_flags/src/feature_flags.rs b/crates/feature_flags/src/feature_flags.rs index 1d36fc0b7e..3434474a06 100644 --- a/crates/feature_flags/src/feature_flags.rs +++ b/crates/feature_flags/src/feature_flags.rs @@ -252,7 +252,7 @@ impl FeatureFlagAppExt for App { fn wait_for_flag_or_timeout(&mut self, timeout: Duration) -> Task { let wait_for_flag = self.wait_for_flag::(); - 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)); diff --git a/crates/feedback/src/feedback.rs b/crates/feedback/src/feedback.rs index ddac6f446e..635f90637b 100644 --- a/crates/feedback/src/feedback.rs +++ b/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)); diff --git a/crates/feedback/src/feedback_modal.rs b/crates/feedback/src/feedback_modal.rs index f53b7e3755..f3cba09bc1 100644 --- a/crates/feedback/src/feedback_modal.rs +++ b/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) { 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(); })), diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 0584a0155e..305ed69d97 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -145,11 +145,11 @@ impl FileFinder { } }) .collect::>(); - 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>, ) -> 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::() { 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(()) }) diff --git a/crates/file_finder/src/new_path_prompt.rs b/crates/file_finder/src/new_path_prompt.rs index 5dc4f2c7e5..cf6789a3e6 100644 --- a/crates/file_finder/src/new_path_prompt.rs +++ b/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; diff --git a/crates/file_finder/src/open_path_prompt.rs b/crates/file_finder/src/open_path_prompt.rs index cf80813785..b778328cfb 100644 --- a/crates/file_finder/src/open_path_prompt.rs +++ b/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 diff --git a/crates/git/src/fake_repository.rs b/crates/git/src/fake_repository.rs index f5b1655b92..553dc6331b 100644 --- a/crates/git/src/fake_repository.rs +++ b/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> { let state = self.state.lock(); let result = state diff --git a/crates/git/src/repository.rs b/crates/git/src/repository.rs index ce0df6ab42..8315773f82 100644 --- a/crates/git/src/repository.rs +++ b/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>; /// 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> { let working_directory = self.working_directory(); let git_binary_path = self.git_binary_path.clone(); diff --git a/crates/git_ui/src/branch_picker.rs b/crates/git_ui/src/branch_picker.rs index 00df617a7a..2c15a667e8 100644 --- a/crates/git_ui/src/branch_picker.rs +++ b/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 = 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(()) diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index d48210f9d5..c54f9d7b87 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/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 { 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(); diff --git a/crates/git_ui/src/onboarding.rs b/crates/git_ui/src/onboarding.rs index 68a4a3f420..3f3dcd6739 100644 --- a/crates/git_ui/src/onboarding.rs +++ b/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 { diff --git a/crates/git_ui/src/picker_prompt.rs b/crates/git_ui/src/picker_prompt.rs index 7de17c0cee..ea67268668 100644 --- a/crates/git_ui/src/picker_prompt.rs +++ b/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>, ) -> 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() { diff --git a/crates/git_ui/src/project_diff.rs b/crates/git_ui/src/project_diff.rs index 32b6609f21..fc8b3945c5 100644 --- a/crates/git_ui/src/project_diff.rs +++ b/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, 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>> { - 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)) }) diff --git a/crates/git_ui/src/repository_selector.rs b/crates/git_ui/src/repository_selector.rs index 683e85e45d..bfe4399535 100644 --- a/crates/git_ui/src/repository_selector.rs +++ b/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(); diff --git a/crates/go_to_line/src/cursor_position.rs b/crates/go_to_line/src/cursor_position.rs index d9f8e474c5..6910926de8 100644 --- a/crates/go_to_line/src/cursor_position.rs +++ b/crates/go_to_line/src/cursor_position.rs @@ -72,11 +72,9 @@ impl CursorPosition { cx: &mut Context, ) { 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(); diff --git a/crates/gpui/examples/opacity.rs b/crates/gpui/examples/opacity.rs index 43c8950f37..796ae08c5f 100644 --- a/crates/gpui/examples/opacity.rs +++ b/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; } })); } diff --git a/crates/gpui/examples/window.rs b/crates/gpui/examples/window.rs index 8b2544bfc1..8feb811ea2 100644 --- a/crates/gpui/examples/window.rs +++ b/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); diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 83316dcbe1..2129daae84 100644 --- a/crates/gpui/src/app.rs +++ b/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(&self, f: impl FnOnce(AsyncApp) -> Fut) -> Task + pub fn spawn(&self, f: AsyncFn) -> Task where - Fut: Future + '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 diff --git a/crates/gpui/src/app/async_context.rs b/crates/gpui/src/app/async_context.rs index 2f8347dbe0..4e27e06350 100644 --- a/crates/gpui/src/app/async_context.rs +++ b/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(&self, f: impl FnOnce(AsyncApp) -> Fut) -> Task + pub fn spawn(&self, f: AsyncFn) -> Task where - Fut: Future + '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( + &self, + entity: &WeakEntity, + f: impl FnOnce(&mut T, &mut Context) + 'static, + ) -> util::Deferred { + 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(&self, f: impl FnOnce(AsyncWindowContext) -> Fut) -> Task + pub fn spawn(&self, f: AsyncFn) -> Task where - Fut: Future + '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. diff --git a/crates/gpui/src/app/context.rs b/crates/gpui/src/app/context.rs index 526a116b6c..a425471717 100644 --- a/crates/gpui/src/app/context.rs +++ b/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(&self, f: impl FnOnce(WeakEntity, AsyncApp) -> Fut) -> Task + pub fn spawn(&self, f: AsyncFn) -> Task where T: 'static, - Fut: Future + 'static, + AsyncFn: AsyncFnOnce(WeakEntity, &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) + 'static, + ) -> Deferred { + 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(&mut self, view: &Entity, 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( - &self, - window: &Window, - f: impl FnOnce(WeakEntity, AsyncWindowContext) -> Fut, - ) -> Task + pub fn spawn_in(&self, window: &Window, f: AsyncFn) -> Task where R: 'static, - Fut: Future + 'static, + AsyncFn: AsyncFnOnce(WeakEntity, &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. diff --git a/crates/gpui/src/elements/div.rs b/crates/gpui/src/elements/div.rs index 7a9078551a..3e8f497b1a 100644 --- a/crates/gpui/src/elements/div.rs +++ b/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; diff --git a/crates/gpui/src/elements/img.rs b/crates/gpui/src/elements/img.rs index 45bf4ada8e..2ef9767092 100644 --- a/crates/gpui/src/elements/img.rs +++ b/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); diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 6650b9440c..4642db46c6 100644 --- a/crates/gpui/src/window.rs +++ b/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(&self, cx: &App, f: impl FnOnce(AsyncWindowContext) -> Fut) -> Task + pub fn spawn(&self, cx: &App, f: AsyncFn) -> Task where R: 'static, - Fut: Future + '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 diff --git a/crates/image_viewer/src/image_viewer.rs b/crates/image_viewer/src/image_viewer.rs index 81c963411b..72b4ed22c1 100644 --- a/crates/image_viewer/src/image_viewer.rs +++ b/crates/image_viewer/src/image_viewer.rs @@ -209,18 +209,18 @@ impl SerializableItem for ImageView { window: &mut Window, cx: &mut App, ) -> Task>> { - 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> { - 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 }) } diff --git a/crates/inline_completion_button/src/inline_completion_button.rs b/crates/inline_completion_button/src/inline_completion_button.rs index 5b35807987..95ab87255e 100644 --- a/crates/inline_completion_button/src/inline_completion_button.rs +++ b/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, - 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::(); diff --git a/crates/journal/src/journal.rs b/crates/journal/src/journal.rs index af46609ef4..0219a1efed 100644 --- a/crates/journal/src/journal.rs +++ b/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::().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]) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 34632fa26b..0d84f1d0d6 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -1304,8 +1304,8 @@ impl Buffer { pub fn reload(&mut self, cx: &Context) -> oneshot::Receiver> { 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(); diff --git a/crates/language/src/language_registry.rs b/crates/language/src/language_registry.rs index f6b5940028..d4deca5944 100644 --- a/crates/language/src/language_registry.rs +++ b/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 { 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()); diff --git a/crates/language_model_selector/src/language_model_selector.rs b/crates/language_model_selector/src/language_model_selector.rs index 73af32816e..e70e951140 100644 --- a/crates/language_model_selector/src/language_model_selector.rs +++ b/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::>(); - 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::>(); - 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() { diff --git a/crates/language_models/src/provider/anthropic.rs b/crates/language_models/src/provider/anthropic.rs index cc55d11595..3bc6460ac7 100644 --- a/crates/language_models/src/provider/anthropic.rs +++ b/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); diff --git a/crates/language_models/src/provider/bedrock.rs b/crates/language_models/src/provider/bedrock.rs index e5702cabba..894b04a2e7 100644 --- a/crates/language_models/src/provider/bedrock.rs +++ b/crates/language_models/src/provider/bedrock.rs @@ -90,12 +90,12 @@ pub struct State { impl State { fn reset_credentials(&self, cx: &mut Context) -> Task> { let credentials_provider = ::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, ) -> Task> { let credentials_provider = ::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 = ::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); diff --git a/crates/language_models/src/provider/cloud.rs b/crates/language_models/src/provider/cloud.rs index 499d6da9db..58eef9aafc 100644 --- a/crates/language_models/src/provider/cloud.rs +++ b/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) -> Task> { 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) { 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(); diff --git a/crates/language_models/src/provider/copilot_chat.rs b/crates/language_models/src/provider/copilot_chat.rs index 70221a318d..3d41144fc6 100644 --- a/crates/language_models/src/provider/copilot_chat.rs +++ b/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 }); diff --git a/crates/language_models/src/provider/deepseek.rs b/crates/language_models/src/provider/deepseek.rs index 33d299375c..760d6b538b 100644 --- a/crates/language_models/src/provider/deepseek.rs +++ b/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(); } diff --git a/crates/language_models/src/provider/google.rs b/crates/language_models/src/provider/google.rs index 79016c8396..59a16b15a7 100644 --- a/crates/language_models/src/provider/google.rs +++ b/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); diff --git a/crates/language_models/src/provider/lmstudio.rs b/crates/language_models/src/provider/lmstudio.rs index 269c6df98b..28f4f46de0 100644 --- a/crates/language_models/src/provider/lmstudio.rs +++ b/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 = 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, cx: &mut Context) -> 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(); }) diff --git a/crates/language_models/src/provider/mistral.rs b/crates/language_models/src/provider/mistral.rs index 2bafeab8c1..d9d62e83b9 100644 --- a/crates/language_models/src/provider/mistral.rs +++ b/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); diff --git a/crates/language_models/src/provider/ollama.rs b/crates/language_models/src/provider/ollama.rs index 4c5de94f97..16cac27f40 100644 --- a/crates/language_models/src/provider/ollama.rs +++ b/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 = 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, window: &mut Window, cx: &mut Context) -> 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(); }) diff --git a/crates/language_models/src/provider/open_ai.rs b/crates/language_models/src/provider/open_ai.rs index f4ec21771a..e914a848b3 100644 --- a/crates/language_models/src/provider/open_ai.rs +++ b/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); diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index d4b661ed9d..24b43a5acf 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/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 diff --git a/crates/language_tools/src/lsp_log.rs b/crates/language_tools/src/lsp_log.rs index 12ab583d96..62f9889a80 100644 --- a/crates/language_tools/src/lsp_log.rs +++ b/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::( - 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); }) } diff --git a/crates/languages/src/go.rs b/crates/languages/src/go.rs index 94815a9951..51e5b2112d 100644 --- a/crates/languages/src/go.rs +++ b/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) diff --git a/crates/languages/src/lib.rs b/crates/languages/src/lib.rs index 29afa3f0a9..a926354a9e 100644 --- a/crates/languages/src/lib.rs +++ b/crates/languages/src/lib.rs @@ -284,7 +284,7 @@ pub fn init(languages: Arc, 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 { diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index 26e1ae1467..4365ce6b02 100644 --- a/crates/languages/src/python.rs +++ b/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(), diff --git a/crates/livekit_client/examples/test_app.rs b/crates/livekit_client/examples/test_app.rs index 458badd5e3..ff680cad19 100644 --- a/crates/livekit_client/examples/test_app.rs +++ b/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(); diff --git a/crates/livekit_client/src/remote_video_track_view.rs b/crates/livekit_client/src/remote_video_track_view.rs index 13e5cfd8bb..5602c829c6 100644 --- a/crates/livekit_client/src/remote_video_track_view.rs +++ b/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 _; diff --git a/crates/livekit_client_macos/examples/test_app_macos.rs b/crates/livekit_client_macos/examples/test_app_macos.rs index fefe08e5f8..df0e0a3769 100644 --- a/crates/livekit_client_macos/examples/test_app_macos.rs +++ b/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, diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index de7e587164..b4d9782920 100644 --- a/crates/lsp/src/lsp.rs +++ b/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, Value, AsyncApp)>; +type NotificationHandler = Box, Value, &mut AsyncApp)>; type ResponseHandler = Box)>; type IoHandler = Box; @@ -309,7 +309,7 @@ impl LanguageServer { root_path: &Path, code_action_kinds: Option>, workspace_folders: Arc>>, - cx: AsyncApp, + cx: &mut AsyncApp, ) -> Result { let working_dir = if root_path.is_dir() { root_path @@ -383,7 +383,7 @@ impl LanguageServer { binary: LanguageServerBinary, root_uri: Url, workspace_folders: Arc>>, - 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>>, response_handlers: Arc>>>, io_handlers: Arc>>, - 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, cx: &App, ) -> Task>> { - cx.spawn(|_| async move { + cx.spawn(async move |_| { let response = self.request::(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(&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>, { self.on_custom_request(T::METHOD, f) @@ -929,7 +934,7 @@ impl LanguageServer { #[must_use] fn on_custom_notification(&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(&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>, 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(); diff --git a/crates/markdown/src/markdown.rs b/crates/markdown/src/markdown.rs index 54f128eca2..7220dfb919 100644 --- a/crates/markdown/src/markdown.rs +++ b/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; diff --git a/crates/markdown_preview/src/markdown_preview_view.rs b/crates/markdown_preview/src/markdown_preview_view.rs index b3760b0da5..13fee8737c 100644 --- a/crates/markdown_preview/src/markdown_preview_view.rs +++ b/crates/markdown_preview/src/markdown_preview_view.rs @@ -372,13 +372,13 @@ impl MarkdownPreviewView { ) -> Task> { 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(); diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 3c9ad17541..aad3c28eff 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/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, diff --git a/crates/notifications/src/notification_store.rs b/crates/notifications/src/notification_store.rs index ae6b761b5f..f6eaaab2f1 100644 --- a/crates/notifications/src/notification_store.rs +++ b/crates/notifications/src/notification_store.rs @@ -76,20 +76,20 @@ impl NotificationStore { pub fn new(client: Arc, user_store: Entity, cx: &mut Context) -> 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, envelope: TypedEnvelope, - 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, notifications: Vec, 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, diff --git a/crates/outline_panel/src/outline_panel.rs b/crates/outline_panel/src/outline_panel.rs index a8f3c7fe09..3113087021 100644 --- a/crates/outline_panel/src/outline_panel.rs +++ b/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::>::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) { - 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"); diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 8e2e258356..f1ae89df82 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -578,8 +578,8 @@ impl Picker { // 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 Picker { .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 Picker { fn hide_scrollbar(&mut self, cx: &mut Context) { 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(); }) diff --git a/crates/prettier/src/prettier.rs b/crates/prettier/src/prettier.rs index 836f5df9cc..66ce046cea 100644 --- a/crates/prettier/src/prettier.rs +++ b/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 { use lsp::{LanguageServerBinary, LanguageServerName}; @@ -280,7 +280,7 @@ impl Prettier { &prettier_dir, None, Default::default(), - cx.clone(), + &mut cx, ) .context("prettier server creation")?; diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index d3a0f5788c..6044052c93 100644 --- a/crates/project/src/buffer_store.rs +++ b/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, ) -> Task> { - 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) -> Task>> { - 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, ) -> Task> { - 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, diff --git a/crates/project/src/connection_manager.rs b/crates/project/src/connection_manager.rs index b3784acf62..c3611089bc 100644 --- a/crates/project/src/connection_manager.rs +++ b/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); @@ -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, client: Arc, - 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(()) diff --git a/crates/project/src/debounced_delay.rs b/crates/project/src/debounced_delay.rs index 6e5767c522..e6fc2e0a35 100644 --- a/crates/project/src/debounced_delay.rs +++ b/crates/project/src/debounced_delay.rs @@ -35,7 +35,7 @@ impl DebouncedDelay { 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 DebouncedDelay { _ = 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; } })); diff --git a/crates/project/src/debugger/breakpoint_store.rs b/crates/project/src/debugger/breakpoint_store.rs index 19297a924d..0a088c8808 100644 --- a/crates/project/src/debugger/breakpoint_store.rs +++ b/crates/project/src/debugger/breakpoint_store.rs @@ -448,7 +448,7 @@ impl BreakpointStore { ) -> Task> { 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(); })?; diff --git a/crates/project/src/debugger/dap_store.rs b/crates/project/src/debugger/dap_store.rs index abfea3b47e..b0c22ba791 100644 --- a/crates/project/src/debugger/dap_store.rs +++ b/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, diff --git a/crates/project/src/debugger/session.rs b/crates/project/src/debugger/session.rs index 931aba5551..086b6df7b5 100644 --- a/crates/project/src/debugger/session.rs +++ b/crates/project/src/debugger/session.rs @@ -191,8 +191,8 @@ impl LocalMode { messages_tx: futures::channel::mpsc::UnboundedSender, cx: AsyncApp, ) -> Task> { - 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>> { 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, 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, 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() }) diff --git a/crates/project/src/environment.rs b/crates/project/src/environment.rs index ad550ce0d9..b04dbe5386 100644 --- a/crates/project/src/environment.rs +++ b/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>> { 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) }) diff --git a/crates/project/src/git.rs b/crates/project/src/git.rs index 1695cd59a0..c7afc90228 100644 --- a/crates/project/src/git.rs +++ b/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, buffer_entity: Entity, - mut cx: AsyncApp, + cx: &mut AsyncApp, ) -> Result> { 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) -> mpsc::UnboundedSender { let (job_tx, mut job_rx) = mpsc::unbounded::(); - 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, cx: &mut Context, ) -> Task>> { - 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, diff --git a/crates/project/src/image_store.rs b/crates/project/src/image_store.rs index 73700e5532..9ccbdb044d 100644 --- a/crates/project/src/image_store.rs +++ b/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 { 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 { 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 { images: HashSet>, cx: &mut Context, ) -> Task> { - 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? } } diff --git a/crates/project/src/lsp_command.rs b/crates/project/src/lsp_command.rs index fac968be78..ee2afe2f54 100644 --- a/crates/project/src/lsp_command.rs +++ b/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 }) diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index b791e15f23..ea91ab8614 100644 --- a/crates/project/src/lsp_store.rs +++ b/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?; + 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(), - &mut cx, - ) - .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); } - - 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(); - } - })?; - - language_server - .notify::( - &did_change_configuration_params, - ) - .ok(); - - anyhow::Ok(language_server) + (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) + })??; + + Self::setup_lsp_messages( + this.clone(), + fs, + &language_server, + delegate.clone(), + adapter.clone(), + ); + + 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(cx, |_, cx| { + cx.emit(LspStoreEvent::LanguageServerRemoved(server_id)) + }) + .ok(); + } + })?; + + language_server + .notify::( + &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::({ 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::({ 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::({ 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::({ 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::({ 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::({ 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::({ 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::({ 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::({ 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::({ 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::({ 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::({ 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>, kind: CodeActionKind, push_to_history: bool, - mut cx: AsyncApp, + cx: &mut AsyncApp, ) -> anyhow::Result { // 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, push_to_history: bool, trigger: FormatTrigger, - mut cx: AsyncApp, + cx: &mut AsyncApp, ) -> anyhow::Result { // 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, - mut cx: AsyncApp, + cx: &mut AsyncApp, ) -> Result { 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::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::(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, ) -> Task> { 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::>(); 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::>()?, }) .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::( 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::, 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, fs: Arc, - 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 @@ -6076,7 +6062,7 @@ impl LspStore { language_server_name: LanguageServerName, cx: &mut Context, ) -> Task>> { - cx.spawn(move |lsp_store, mut cx| async move { + cx.spawn(async move |lsp_store, cx| { // Escape percent-encoded string. let current_scheme = abs_path.scheme().to_owned(); let _ = abs_path.set_scheme("file"); @@ -6086,13 +6072,11 @@ impl LspStore { .map_err(|_| anyhow!("can't convert URI to path"))?; let p = abs_path.clone(); let yarn_worktree = lsp_store - .update(&mut cx, move |lsp_store, cx| match lsp_store.as_local() { + .update(cx, move |lsp_store, cx| match lsp_store.as_local() { Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| { - cx.spawn(|this, mut cx| async move { + cx.spawn(async move |this, cx| { let t = this - .update(&mut cx, |this, cx| { - this.process_path(&p, ¤t_scheme, cx) - }) + .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx)) .ok()?; t.await }) @@ -6107,7 +6091,7 @@ impl LspStore { (Arc::::from(abs_path.as_path()), None) }; let (worktree, relative_path) = if let Some(result) = - lsp_store.update(&mut cx, |lsp_store, cx| { + lsp_store.update(cx, |lsp_store, cx| { lsp_store.worktree_store.update(cx, |worktree_store, cx| { worktree_store.find_worktree(&worktree_root_target, cx) }) @@ -6117,15 +6101,15 @@ impl LspStore { (result.0, relative_path) } else { let worktree = lsp_store - .update(&mut cx, |lsp_store, cx| { + .update(cx, |lsp_store, cx| { lsp_store.worktree_store.update(cx, |worktree_store, cx| { worktree_store.create_worktree(&worktree_root_target, false, cx) }) })? .await?; - if worktree.update(&mut cx, |worktree, _| worktree.is_local())? { + if worktree.update(cx, |worktree, _| worktree.is_local())? { lsp_store - .update(&mut cx, |lsp_store, cx| { + .update(cx, |lsp_store, cx| { lsp_store.register_local_language_server( worktree.clone(), language_server_name, @@ -6135,7 +6119,7 @@ impl LspStore { }) .ok(); } - let worktree_root = worktree.update(&mut cx, |worktree, _| worktree.abs_path())?; + let worktree_root = worktree.update(cx, |worktree, _| worktree.abs_path())?; let relative_path = if let Some(known_path) = known_relative_path { known_path } else { @@ -6144,11 +6128,11 @@ impl LspStore { (worktree, relative_path) }; let project_path = ProjectPath { - worktree_id: worktree.update(&mut cx, |worktree, _| worktree.id())?, + worktree_id: worktree.update(cx, |worktree, _| worktree.id())?, path: relative_path, }; lsp_store - .update(&mut cx, |lsp_store, cx| { + .update(cx, |lsp_store, cx| { lsp_store.buffer_store().update(cx, |buffer_store, cx| { buffer_store.open_buffer(project_path, cx) }) @@ -6202,7 +6186,7 @@ impl LspStore { }) .collect::>(); - cx.spawn(|_, _| async move { + cx.spawn(async move |_, _| { let mut responses = Vec::with_capacity(response_results.len()); while let Some(response_result) = response_results.next().await { if let Some(response) = response_result.log_err() { @@ -6793,13 +6777,13 @@ impl LspStore { return; } - let prev_task = simulate_disk_based_diagnostics_completion.replace(cx.spawn( - move |this, mut cx| async move { + let prev_task = + simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| { cx.background_executor() .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE) .await; - this.update(&mut cx, |this, cx| { + this.update(cx, |this, cx| { this.disk_based_diagnostics_finished(language_server_id, cx); if let Some(LanguageServerState::Running { @@ -6812,8 +6796,7 @@ impl LspStore { } }) .ok(); - }, - )); + })); if prev_task.is_none() { self.disk_based_diagnostics_started(language_server_id, cx); @@ -6874,9 +6857,9 @@ impl LspStore { ) -> Task<()> { let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from); let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from); - cx.spawn(move |mut cx| async move { + cx.spawn(async move |cx| { let mut tasks = vec![]; - this.update(&mut cx, |this, cx| { + this.update(cx, |this, cx| { let local_store = this.as_local()?; let old_uri = old_uri?; let new_uri = new_uri?; @@ -6897,7 +6880,7 @@ impl LspStore { let old_uri = old_uri.clone(); let new_uri = new_uri.clone(); let language_server = language_server.clone(); - |this, mut cx| async move { + async move |this, cx| { let edit = language_server .request::(RenameFilesParams { files: vec![FileRename { old_uri, new_uri }], @@ -6912,7 +6895,7 @@ impl LspStore { false, adapter.clone(), language_server.clone(), - &mut cx, + cx, ) .await .ok(); @@ -7587,12 +7570,12 @@ impl LspStore { }) .collect::>(); - cx.spawn(move |lsp_store, mut cx| async move { + cx.spawn(async move |lsp_store, cx| { let mut formattable_buffers = Vec::with_capacity(buffers.len()); for (handle, abs_path, id) in buffers { let env = lsp_store - .update(&mut cx, |lsp_store, cx| { + .update(cx, |lsp_store, cx| { lsp_store.environment_for_buffer(&handle, cx) })? .await; @@ -7620,10 +7603,10 @@ impl LspStore { formattable_buffers, push_to_history, trigger, - cx.clone(), + cx, ) .await; - lsp_store.update(&mut cx, |lsp_store, _| { + lsp_store.update(cx, |lsp_store, _| { lsp_store.update_last_formatting_failure(&result); })?; @@ -7639,28 +7622,26 @@ impl LspStore { } 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::FormatBuffers { project_id, trigger: trigger as i32, 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::>()?, }) .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, @@ -7750,7 +7731,7 @@ impl LspStore { async fn shutdown_language_server( server_state: Option, name: LanguageServerName, - cx: AsyncApp, + cx: &mut AsyncApp, ) { let server = match server_state { Some(LanguageServerState::Starting { startup, .. }) => { @@ -7862,7 +7843,7 @@ impl LspStore { let server_state = local.language_servers.remove(&server_id); cx.notify(); cx.emit(LspStoreEvent::LanguageServerRemoved(server_id)); - cx.spawn(move |_, cx| async move { + cx.spawn(async move |_, cx| { Self::shutdown_language_server(server_state, name, cx).await; orphaned_worktrees }) @@ -7909,9 +7890,9 @@ impl LspStore { }) .collect::>(); - cx.spawn(|this, mut cx| async move { + cx.spawn(async move |this, cx| { cx.background_spawn(futures::future::join_all(tasks)).await; - this.update(&mut cx, |this, cx| { + this.update(cx, |this, cx| { for buffer in buffers { this.register_buffer_with_language_servers(&buffer, true, cx); } @@ -8871,12 +8852,12 @@ impl LanguageServerWatchedPathsBuilder { let fs = fs.clone(); let lsp_store = project.clone(); - |_, mut cx| async move { + async move |_, cx| { maybe!(async move { let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await; while let Some(update) = push_updates.0.next().await { let action = lsp_store - .update(&mut cx, |this, _| { + .update(cx, |this, _| { let Some(local) = this.as_local() else { return ControlFlow::Break(()); }; diff --git a/crates/project/src/lsp_store/clangd_ext.rs b/crates/project/src/lsp_store/clangd_ext.rs index 390eb735bc..8b8f6eaba7 100644 --- a/crates/project/src/lsp_store/clangd_ext.rs +++ b/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() diff --git a/crates/project/src/lsp_store/rust_analyzer_ext.rs b/crates/project/src/lsp_store/rust_analyzer_ext.rs index d049ac2c4e..191c6b5a91 100644 --- a/crates/project/src/lsp_store/rust_analyzer_ext.rs +++ b/crates/project/src/lsp_store/rust_analyzer_ext.rs @@ -51,7 +51,7 @@ pub fn register_notifications(lsp_store: WeakEntity, language_server: language_server .on_notification::({ 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, language_server: lsp_name: name.clone(), }; let _ = this - .update(&mut cx, |_, cx| { + .update(cx, |_, cx| { cx.emit(LspStoreEvent::LanguageServerPrompt(request)); }) .ok(); diff --git a/crates/project/src/prettier_store.rs b/crates/project/src/prettier_store.rs index 91da792ae3..0b78effca8 100644 --- a/crates/project/src/prettier_store.rs +++ b/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, cx: &mut Context, ) -> 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, cx: &mut Context, ) -> Task> { - 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 diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index c70edeb547..b36dea1f8d 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -810,7 +810,7 @@ impl Project { ) -> Entity { cx.new(|cx: &mut Context| { 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 { cx.new(|cx: &mut Context| { 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, ) -> Task, 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, ) -> Task, 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>, cx: &mut Context, ) -> Task> { - 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, rx: UnboundedReceiver, - 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) -> 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::>(); - 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::>(); + 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> { 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() diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 43b17a2d8d..787efa20ff 100644 --- a/crates/project/src/project_settings.rs +++ b/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, _, _)> = futures::future::join_all(settings_contents).await; cx.update(|cx| { diff --git a/crates/project/src/task_store.rs b/crates/project/src/task_store.rs index 0d1ccc270d..359d100abe 100644 --- a/crates/project/src/task_store.rs +++ b/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, cx: &mut App, ) -> Task> { - 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( diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index e34a2381d8..d3a9acc11e 100644 --- a/crates/project/src/terminals.rs +++ b/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, ) -> Task> { - 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); } diff --git a/crates/project/src/toolchain_store.rs b/crates/project/src/toolchain_store.rs index 8464eff6a1..b33e4913a3 100644 --- a/crates/project/src/toolchain_store.rs +++ b/crates/project/src/toolchain_store.rs @@ -288,8 +288,8 @@ impl LocalToolchainStore { toolchain: Toolchain, cx: &mut Context, ) -> Task> { - 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> { 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> { 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> { 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, diff --git a/crates/project/src/worktree_store.rs b/crates/project/src/worktree_store.rs index 800d0e68e7..ee8539c738 100644 --- a/crates/project/src/worktree_store.rs +++ b/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::>(); for worktree in worktrees { diff --git a/crates/project/src/yarn.rs b/crates/project/src/yarn.rs index 9f0464f35d..64349e2911 100644 --- a/crates/project/src/yarn.rs +++ b/crates/project/src/yarn.rs @@ -91,9 +91,9 @@ impl YarnPathStore { }; if let Some(zip_file) = zip_path(&path) { let zip_file: Arc = 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()?; diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index a85663e170..5246374505 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/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(); + 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; - } - })); + 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>>> { 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 { diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index c22710731d..eaabac5d6f 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/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 diff --git a/crates/prompt_library/src/prompt_library.rs b/crates/prompt_library/src/prompt_library.rs index 7b7b13d0b2..f68d4a4b85 100644 --- a/crates/prompt_library/src/prompt_library.rs +++ b/crates/prompt_library/src/prompt_library.rs @@ -78,7 +78,7 @@ pub fn open_prompt_library( cx: &mut App, ) -> Task>> { 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 }); } } diff --git a/crates/recent_projects/src/disconnected_overlay.rs b/crates/recent_projects/src/disconnected_overlay.rs index ecc303fc19..ff5883a0d2 100644 --- a/crates/recent_projects/src/disconnected_overlay.rs +++ b/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(()) diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index 5fef444d06..45fa03dbf1 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/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 diff --git a/crates/recent_projects/src/remote_servers.rs b/crates/recent_projects/src/remote_servers.rs index 5e7a9be2d3..6308b6843c 100644 --- a/crates/recent_projects/src/remote_servers.rs +++ b/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::>(); 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::(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(); }) diff --git a/crates/recent_projects/src/ssh_connections.rs b/crates/recent_projects/src/ssh_connections.rs index 315a80a11b..68a1b70061 100644 --- a/crates/recent_projects/src/ssh_connections.rs +++ b/crates/recent_projects/src/ssh_connections.rs @@ -455,13 +455,13 @@ impl remote::SshClientDelegate for SshClientDelegate { version: Option, cx: &mut AsyncApp, ) -> Task> { - 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, cx: &mut AsyncApp, ) -> Task>> { - 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 }) diff --git a/crates/remote/src/ssh_session.rs b/crates/remote/src/ssh_session.rs index d254526e18..9eff5c811d 100644 --- a/crates/remote/src/ssh_session.rs +++ b/crates/remote/src/ssh_session.rs @@ -615,7 +615,7 @@ impl SshRemoteClient { cx: &mut App, ) -> Task>>> { 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::(); let (incoming_tx, incoming_rx) = mpsc::unbounded::(); @@ -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>, cx: &AsyncApp, ) -> Task> { - 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); @@ -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, cx: &AsyncApp, ) -> Task> { - 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 { diff --git a/crates/remote_server/src/headless_project.rs b/crates/remote_server/src/headless_project.rs index 848bdaad55..46db74515f 100644 --- a/crates/remote_server/src/headless_project.rs +++ b/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, cx: AsyncApp, ) -> Result { - 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. diff --git a/crates/remote_server/src/unix.rs b/crates/remote_server/src/unix.rs index d7eabaf648..3e3126c649 100644 --- a/crates/remote_server/src/unix.rs +++ b/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); diff --git a/crates/repl/src/kernels/native_kernel.rs b/crates/repl/src/kernels/native_kernel.rs index 7170b43234..0ed933c626 100644 --- a/crates/repl/src/kernels/native_kernel.rs +++ b/crates/repl/src/kernels/native_kernel.rs @@ -118,7 +118,7 @@ impl NativeRunningKernel { window: &mut Window, cx: &mut App, ) -> Task>> { - 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(); diff --git a/crates/repl/src/kernels/remote_kernels.rs b/crates/repl/src/kernels/remote_kernels.rs index 6c8d8e2b26..fd487e56ca 100644 --- a/crates/repl/src/kernels/remote_kernels.rs +++ b/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) diff --git a/crates/repl/src/notebook/cell.rs b/crates/repl/src/notebook/cell.rs index 8666fd89be..7d0a35ccdc 100644 --- a/crates/repl/src/notebook/cell.rs +++ b/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); }); }); diff --git a/crates/repl/src/notebook/notebook_ui.rs b/crates/repl/src/notebook/notebook_ui.rs index eaa7cb97f1..786696a309 100644 --- a/crates/repl/src/notebook/notebook_ui.rs +++ b/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 let mut cell_map = HashMap::default(); // HashMap @@ -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; diff --git a/crates/repl/src/outputs/markdown.rs b/crates/repl/src/outputs/markdown.rs index b29c9c82ae..a5013f691b 100644 --- a/crates/repl/src/outputs/markdown.rs +++ b/crates/repl/src/outputs/markdown.rs @@ -17,20 +17,18 @@ pub struct MarkdownView { impl MarkdownView { pub fn from(text: String, cx: &mut Context) -> 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 }); + 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; - async move { - 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 { diff --git a/crates/repl/src/repl_store.rs b/crates/repl/src/repl_store.rs index 7293c8483d..8597cedadd 100644 --- a/crates/repl/src/repl_store.rs +++ b/crates/repl/src/repl_store.rs @@ -122,12 +122,12 @@ impl ReplStore { cx: &mut Context, ) -> Task> { 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(); }) diff --git a/crates/repl/src/session.rs b/crates/repl/src/session.rs index f2d3259e67..08aaeb605e 100644 --- a/crates/repl/src/session.rs +++ b/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); diff --git a/crates/reqwest_client/examples/client.rs b/crates/reqwest_client/examples/client.rs index fa204638da..3a94ca4a83 100644 --- a/crates/reqwest_client/examples/client.rs +++ b/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 = [ diff --git a/crates/scripting_tool/src/scripting_session.rs b/crates/scripting_tool/src/scripting_session.rs index 3da14e5aa8..65a7108f91 100644 --- a/crates/scripting_tool/src/scripting_session.rs +++ b/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 { diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index b78a35602e..93a0bb52c0 100644 --- a/crates/search/src/buffer_search.rs +++ b/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) { diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 5a89efa1bd..4010554882 100644 --- a/crates/search/src/project_search.rs +++ b/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); }) diff --git a/crates/semantic_index/examples/index.rs b/crates/semantic_index/examples/index.rs index 236d4a8d36..1b90de7749 100644 --- a/crates/semantic_index/examples/index.rs +++ b/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; diff --git a/crates/semantic_index/src/embedding_index.rs b/crates/semantic_index/src/embedding_index.rs index 6c3c8a40ff..a6a29498eb 100644 --- a/crates/semantic_index/src/embedding_index.rs +++ b/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() { diff --git a/crates/semantic_index/src/project_index.rs b/crates/semantic_index/src/project_index.rs index c99832c7af..e739d9b5b9 100644 --- a/crates/semantic_index/src/project_index.rs +++ b/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::::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), ) diff --git a/crates/semantic_index/src/project_index_debug_view.rs b/crates/semantic_index/src/project_index_debug_view.rs index 1a885f0eb8..44a194ae45 100644 --- a/crates/semantic_index/src/project_index_debug_view.rs +++ b/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) { 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::>(); - this.update(&mut cx, |this, cx| { + this.update(cx, |this, cx| { let view = cx.entity().downgrade(); this.selected_path = Some(PathState { path: file_path, diff --git a/crates/semantic_index/src/summary_index.rs b/crates/semantic_index/src/summary_index.rs index 69168acc6d..42cc1bc64d 100644 --- a/crates/semantic_index/src/summary_index.rs +++ b/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 diff --git a/crates/semantic_index/src/worktree_index.rs b/crates/semantic_index/src/worktree_index.rs index f4ec4a5c6d..f4d4650757 100644 --- a/crates/semantic_index/src/worktree_index.rs +++ b/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, updated_entries: channel::Receiver, - mut cx: AsyncApp, + cx: &mut AsyncApp, ) -> Result<()> { let is_auto_available = cx.update(|cx| cx.wait_for_flag::())?.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::()) .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), diff --git a/crates/session/src/session.rs b/crates/session/src/session.rs index d195d04db2..a37a2ebcbb 100644 --- a/crates/session/src/session.rs +++ b/crates/session/src/session.rs @@ -67,16 +67,14 @@ impl AppSession { pub fn new(session: Session, cx: &Context) -> 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 { diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index 8b60fd88d7..3d78b38374 100644 --- a/crates/settings/src/settings_store.rs +++ b/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(); } diff --git a/crates/snippet_provider/src/lib.rs b/crates/snippet_provider/src/lib.rs index dc625779b3..3058b4ac70 100644 --- a/crates/snippet_provider/src/lib.rs +++ b/crates/snippet_provider/src/lib.rs @@ -181,8 +181,8 @@ impl SnippetProvider { fn watch_directory(&mut self, path: &Path, cx: &Context) { let path: Arc = 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?; diff --git a/crates/snippets_ui/src/snippets_ui.rs b/crates/snippets_ui/src/snippets_ui.rs index fbab1dd4b2..92261c5a8b 100644 --- a/crates/snippets_ui/src/snippets_ui.rs +++ b/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 diff --git a/crates/storybook/src/storybook.rs b/crates/storybook/src/storybook.rs index 0cd93849cd..14793603c7 100644 --- a/crates/storybook/src/storybook.rs +++ b/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(()) }) diff --git a/crates/supermaven/src/supermaven.rs b/crates/supermaven/src/supermaven.rs index a289c7f68b..9c7e0b1c78 100644 --- a/crates/supermaven/src/supermaven.rs +++ b/crates/supermaven/src/supermaven.rs @@ -87,11 +87,11 @@ impl Supermaven { pub fn start(&mut self, client: Arc, cx: &mut Context) { 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, 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); } diff --git a/crates/supermaven/src/supermaven_completion_provider.rs b/crates/supermaven/src/supermaven_completion_provider.rs index 4dc0ebbabb..c49272e66e 100644 --- a/crates/supermaven/src/supermaven_completion_provider.rs +++ b/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| { diff --git a/crates/tasks_ui/src/modal.rs b/crates/tasks_ui/src/modal.rs index b80c551dda..b11d2e7be9 100644 --- a/crates/tasks_ui/src/modal.rs +++ b/crates/tasks_ui/src/modal.rs @@ -217,40 +217,36 @@ impl PickerDelegate for TasksModalDelegate { cx: &mut Context>, ) -> 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 { diff --git a/crates/tasks_ui/src/tasks_ui.rs b/crates/tasks_ui/src/tasks_ui.rs index 9ad810f212..b99884dc75 100644 --- a/crates/tasks_ui/src/tasks_ui.rs +++ b/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, ) -> Task> { - 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 { diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index b2c9b5d35b..4723fce8a4 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -487,9 +487,9 @@ impl TerminalBuilder { pub fn subscribe(mut self, cx: &Context) -> 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; }); } diff --git a/crates/terminal_view/src/persistence.rs b/crates/terminal_view/src/persistence.rs index f66613febe..5668083973 100644 --- a/crates/terminal_view/src/persistence.rs +++ b/crates/terminal_view/src/persistence.rs @@ -90,8 +90,8 @@ pub(crate) fn deserialize_terminal_panel( window: &mut Window, cx: &mut App, ) -> Task>> { - 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()); diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index f3f89281d7..370172cede 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/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, ) -> Task>> { 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::(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::(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, diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 393aeb10ad..66635b12f5 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/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> { - 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>> { 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?; diff --git a/crates/theme_selector/src/icon_theme_selector.rs b/crates/theme_selector/src/icon_theme_selector.rs index 482f6a4984..860bdd585f 100644 --- a/crates/theme_selector/src/icon_theme_selector.rs +++ b/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::>(); - 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 diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index d64591707c..a1737a4f7b 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -266,7 +266,7 @@ impl PickerDelegate for ThemeSelectorDelegate { .map(|(id, meta)| StringMatchCandidate::new(id, &meta.name)) .collect::>(); - 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 diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index 6045c7a5b1..37852dd599 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/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(); }) diff --git a/crates/toolchain_selector/src/active_toolchain.rs b/crates/toolchain_selector/src/active_toolchain.rs index ee93acf38c..41a8b10f92 100644 --- a/crates/toolchain_selector/src/active_toolchain.rs +++ b/crates/toolchain_selector/src/active_toolchain.rs @@ -30,40 +30,38 @@ impl ActiveToolchain { } } fn spawn_tracker_task(window: &mut Window, cx: &mut Context) -> Task> { - 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> { - 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()? diff --git a/crates/toolchain_selector/src/toolchain_selector.rs b/crates/toolchain_selector/src/toolchain_selector.rs index 0a5a643890..c6a5efec48 100644 --- a/crates/toolchain_selector/src/toolchain_selector.rs +++ b/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 diff --git a/crates/ui/src/components/context_menu.rs b/crates/ui/src/components/context_menu.rs index a06bc40b92..df7de5b2e8 100644 --- a/crates/ui/src/components/context_menu.rs +++ b/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; diff --git a/crates/vim/src/command.rs b/crates/vim/src/command.rs index 9b8009a110..f01bb78dc9 100644 --- a/crates/vim/src/command.rs +++ b/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); diff --git a/crates/vim/src/normal/mark.rs b/crates/vim/src/normal/mark.rs index 0dbbeab913..783e918edd 100644 --- a/crates/vim/src/normal/mark.rs +++ b/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::(cx) { editor.update(cx, |editor, cx| { let map = editor.snapshot(window, cx); diff --git a/crates/vim/src/normal/search.rs b/crates/vim/src/normal/search.rs index e32d34f32b..fb79be3195 100644 --- a/crates/vim/src/normal/search.rs +++ b/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(); diff --git a/crates/vim/src/normal/yank.rs b/crates/vim/src/normal/yank.rs index 0367f43dae..2d4e53fd23 100644 --- a/crates/vim/src/normal/yank.rs +++ b/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::(cx) }) .ok(); diff --git a/crates/vim/src/state.rs b/crates/vim/src/state.rs index 7d372ee412..cf68798ffe 100644 --- a/crates/vim/src/state.rs +++ b/crates/vim/src/state.rs @@ -288,8 +288,8 @@ impl MarksState { } fn load(&mut self, cx: &mut Context) { - 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); } diff --git a/crates/welcome/src/base_keymap_picker.rs b/crates/welcome/src/base_keymap_picker.rs index e052062918..031b6a97af 100644 --- a/crates/welcome/src/base_keymap_picker.rs +++ b/crates/welcome/src/base_keymap_picker.rs @@ -130,7 +130,7 @@ impl PickerDelegate for BaseKeymapSelectorDelegate { .map(|(id, name)| StringMatchCandidate::new(id, name)) .collect::>(); - 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 diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index c95dccb2f7..ac36b9cf26 100644 --- a/crates/welcome/src/welcome.rs +++ b/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); diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 8bf0691c75..ff24eab03e 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -718,13 +718,13 @@ impl ItemHandle for Entity { 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, diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index 43d012e418..42c35c3077 100644 --- a/crates/workspace/src/notifications.rs +++ b/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, ix: usize, mut cx: AsyncWindowContext) { + async fn select_option(this: Entity, 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 + 'static, ) -> Task> { 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:?}"); diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 8888ae2a04..babd38e227 100644 --- a/crates/workspace/src/pane.rs +++ b/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); diff --git a/crates/workspace/src/searchable.rs b/crates/workspace/src/searchable.rs index 63f572931c..c8777df032 100644 --- a/crates/workspace/src/searchable.rs +++ b/crates/workspace/src/searchable.rs @@ -303,7 +303,7 @@ impl SearchableItemHandle for Entity { cx: &mut App, ) -> Task> { 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::(matches.len()); { diff --git a/crates/workspace/src/shared_screen/macos.rs b/crates/workspace/src/shared_screen/macos.rs index 29f590adb3..e943b18692 100644 --- a/crates/workspace/src/shared_screen/macos.rs +++ b/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(), diff --git a/crates/workspace/src/toast_layer.rs b/crates/workspace/src/toast_layer.rs index d9cd8ecf73..d06ad53786 100644 --- a/crates/workspace/src/toast_layer.rs +++ b/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(); } }); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index c020bede08..79586f2615 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -368,8 +368,8 @@ pub fn init_settings(cx: &mut App) { fn prompt_and_open_paths(app_state: Arc, 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, options: PathPromptOptions, c }) .ok(); } - } - }) + }, + ) .detach(); } @@ -465,10 +465,10 @@ pub fn register_project_item(cx: &mut App) { builders.push(|project, project_path, window, cx| { let project_item = ::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 = - 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| { Box::new(cx.new(|cx| I::for_project_item(project, project_item, window, cx))) as Box @@ -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::>(); - 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) { 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::>(); 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 = 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, ) -> Task>> { - 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>> { 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) { 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, ) -> Task>>>> { - 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::>(); // 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> { 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) + 'static + Send, ) -> Task> { 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, default_content: impl 'static + Send + FnOnce() -> Rope, ) -> Task>> { - 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, cx: &mut App, ) -> Task> { - 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> { 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::() .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>>> { 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>>> { 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 } diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index 4f31df6da5..a688d45ddb 100644 --- a/crates/worktree/src/worktree.rs +++ b/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::>(); - 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, ) -> Task> { 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:?}")) diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index bb399250c5..3080943d7f 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -109,7 +109,7 @@ fn files_not_created_on_launch(errors: HashMap>) { 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, cx: &App) { fn load_user_themes_in_background(fs: Arc, 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, cx: &mut App) { /// Spawns a background task to watch the themes directory for changes. fn watch_themes(fs: Arc, 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, languages: Arc, 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| { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index f74994d35a..152cc90f7a 100644 --- a/crates/zed/src/zed.rs +++ b/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) { &["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) { &["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::(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, + 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::(); - 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( .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) -> Option { 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, ) { 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, ) { - 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 diff --git a/crates/zed/src/zed/migrate.rs b/crates/zed/src/zed/migrate.rs index a4d1fc06cc..8dbbcc802f 100644 --- a/crates/zed/src/zed/migrate.rs +++ b/crates/zed/src/zed/migrate.rs @@ -121,9 +121,9 @@ impl ToolbarItemView for MigrationBanner { self.migration_type = Some(MigrationType::Keymap); let 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 = ::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 = ::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!(), } diff --git a/crates/zed/src/zed/open_listener.rs b/crates/zed/src/zed/open_listener.rs index 24a8b2b5ca..2bda7bbdc3 100644 --- a/crates/zed/src/zed/open_listener.rs +++ b/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, IpcSender), app_state: Arc, - 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(), diff --git a/crates/zeta/src/onboarding_banner.rs b/crates/zeta/src/onboarding_banner.rs index 37d62e7039..f38d6fd700 100644 --- a/crates/zeta/src/onboarding_banner.rs +++ b/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 { diff --git a/crates/zeta/src/onboarding_modal.rs b/crates/zeta/src/onboarding_modal.rs index f7f30da7df..b452593331 100644 --- a/crates/zeta/src/onboarding_modal.rs +++ b/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::(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() diff --git a/crates/zeta/src/zeta.rs b/crates/zeta/src/zeta.rs index a56eac913d..58aaffb6a5 100644 --- a/crates/zeta/src/zeta.rs +++ b/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 = output_excerpt.into(); let edits: Arc<[(Range, 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 {