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

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

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

Release Notes:

- N/A
This commit is contained in:
Mikayla Maki 2025-03-18 19:09:02 -07:00 committed by GitHub
parent 7f2e3fb5bd
commit 1aefa5178b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
256 changed files with 3110 additions and 3200 deletions

View file

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

View file

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

View file

@ -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 {

View file

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

View file

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

View file

@ -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();