From 94c2eaad23264415586e79afc99e2ff60695e308 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 26 Apr 2023 10:23:27 +0200 Subject: [PATCH] Replace `ViewContext::spawn` with `ViewContext::spawn_weak` --- .../src/activity_indicator.rs | 2 +- .../src/incoming_call_notification.rs | 2 +- crates/context_menu/src/context_menu.rs | 4 +- crates/editor/src/editor.rs | 16 +++---- crates/editor/src/hover_popover.rs | 2 +- crates/editor/src/items.rs | 9 +++- crates/editor/src/link_go_to_definition.rs | 2 +- crates/editor/src/scroll.rs | 2 +- crates/gpui/src/app.rs | 36 +++++++++------- crates/gpui/src/elements/tooltip.rs | 2 +- .../src/language_selector.rs | 4 +- crates/picker/src/picker.rs | 2 +- crates/project_symbols/src/project_symbols.rs | 4 +- crates/search/src/buffer_search.rs | 2 +- crates/terminal_view/src/terminal_view.rs | 43 +++++++++---------- crates/theme_selector/src/theme_selector.rs | 2 +- crates/welcome/src/base_keymap_picker.rs | 2 +- crates/workspace/src/item.rs | 2 +- crates/workspace/src/workspace.rs | 14 +++--- crates/zed/src/zed.rs | 4 +- 20 files changed, 83 insertions(+), 73 deletions(-) diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index 4b58b3ad0a..b893c38885 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -63,7 +63,7 @@ impl ActivityIndicator { let auto_updater = AutoUpdater::get(cx); let this = cx.add_view(|cx: &mut ViewContext| { let mut status_events = languages.language_server_binary_statuses(); - cx.spawn_weak(|this, mut cx| async move { + cx.spawn(|this, mut cx| async move { while let Some((language, event)) = status_events.next().await { if let Some(this) = this.upgrade(&cx) { this.update(&mut cx, |this, cx| { diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index 49c9adb845..d0cf893a0f 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -79,7 +79,7 @@ impl IncomingCallNotification { let join = active_call.update(cx, |active_call, cx| active_call.accept_incoming(cx)); let caller_user_id = self.call.calling_user.id; let initial_project_id = self.call.initial_project.as_ref().map(|project| project.id); - cx.spawn_weak(|_, mut cx| async move { + cx.spawn(|_, mut cx| async move { join.await?; if let Some(project_id) = initial_project_id { cx.update(|cx| { diff --git a/crates/context_menu/src/context_menu.rs b/crates/context_menu/src/context_menu.rs index cba3073caa..01a04cfd22 100644 --- a/crates/context_menu/src/context_menu.rs +++ b/crates/context_menu/src/context_menu.rs @@ -1,4 +1,5 @@ use gpui::{ + anyhow, elements::*, geometry::vector::Vector2F, impl_internal_actions, @@ -209,7 +210,8 @@ impl ContextMenu { cx.notify(); cx.spawn(|this, mut cx| async move { cx.background().timer(Duration::from_millis(50)).await; - this.update(&mut cx, |this, cx| this.cancel(&Default::default(), cx)) + this.update(&mut cx, |this, cx| this.cancel(&Default::default(), cx))?; + anyhow::Ok(()) }) .detach_and_log_err(cx); } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 2fa5eabcd9..f30a19312d 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2477,7 +2477,7 @@ impl Editor { }); let id = post_inc(&mut self.next_completion_id); - let task = cx.spawn_weak(|this, mut cx| { + let task = cx.spawn(|this, mut cx| { async move { let menu = if let Some(completions) = completions.await.log_err() { let mut menu = CompletionsMenu { @@ -2669,7 +2669,7 @@ impl Editor { let deployed_from_indicator = action.deployed_from_indicator; let mut task = self.code_actions_task.take(); - cx.spawn_weak(|this, mut cx| async move { + cx.spawn(|this, mut cx| async move { while let Some(prev_task) = task { prev_task.await; task = this @@ -2731,7 +2731,7 @@ impl Editor { async fn open_project_transaction( this: ViewHandle, - workspace: ViewHandle, + workspace: WeakViewHandle, transaction: ProjectTransaction, title: String, mut cx: AsyncAppContext, @@ -2826,7 +2826,7 @@ impl Editor { let actions = project.update(cx, |project, cx| { project.code_actions(&start_buffer, start..end, cx) }); - self.code_actions_task = Some(cx.spawn_weak(|this, mut cx| async move { + self.code_actions_task = Some(cx.spawn(|this, mut cx| async move { let actions = actions.await; if let Some(this) = this.upgrade(&cx) { this.update(&mut cx, |this, cx| { @@ -2865,7 +2865,7 @@ impl Editor { project.document_highlights(&cursor_buffer, cursor_buffer_position, cx) }); - self.document_highlights_task = Some(cx.spawn_weak(|this, mut cx| async move { + self.document_highlights_task = Some(cx.spawn(|this, mut cx| async move { let highlights = highlights.log_err().await; if let Some((this, highlights)) = this.upgrade(&cx).zip(highlights) { this.update(&mut cx, |this, cx| { @@ -2961,7 +2961,7 @@ impl Editor { let (buffer, buffer_position) = self.buffer.read(cx).text_anchor_for_position(cursor, cx)?; - self.copilot_state.pending_refresh = cx.spawn_weak(|this, mut cx| async move { + self.copilot_state.pending_refresh = cx.spawn(|this, mut cx| async move { if debounce { cx.background().timer(COPILOT_DEBOUNCE_TIMEOUT).await; } @@ -3014,7 +3014,7 @@ impl Editor { let cursor = self.selections.newest_anchor().head(); let (buffer, buffer_position) = self.buffer.read(cx).text_anchor_for_position(cursor, cx)?; - self.copilot_state.pending_cycling_refresh = cx.spawn_weak(|this, mut cx| async move { + self.copilot_state.pending_cycling_refresh = cx.spawn(|this, mut cx| async move { let completions = copilot .update(&mut cx, |copilot, cx| { copilot.completions_cycling(&buffer, buffer_position, cx) @@ -6770,7 +6770,7 @@ impl Editor { let editor = workspace.open_path(action.path.clone(), None, true, cx); let position = action.position; let anchor = action.anchor; - cx.spawn_weak(|_, mut cx| async move { + cx.spawn(|_, mut cx| async move { let editor = editor .await? .downcast::() diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 7c62f71bda..5c45ab7751 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -149,7 +149,7 @@ fn show_hover( } } - let task = cx.spawn_weak(|this, mut cx| { + let task = cx.spawn(|this, mut cx| { async move { // If we need to delay, delay a set amount initially before making the lsp request let delay = if !ignore_timeout { diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 01db7de724..058829d1b9 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -3,7 +3,7 @@ use crate::{ movement::surrounding_word, persistence::DB, scroll::ScrollAnchor, Anchor, Autoscroll, Editor, Event, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, NavigationData, ToPoint as _, }; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use collections::HashSet; use futures::future::try_join_all; use gpui::{ @@ -286,6 +286,9 @@ impl FollowableItem for Editor { let update_view::Variant::Editor(message) = message; let project = project.clone(); cx.spawn(|this, mut cx| async move { + let this = this + .upgrade(&cx) + .ok_or_else(|| anyhow!("editor was dropped"))?; update_editor_from_message(this, project, message, &mut cx).await }) } @@ -863,7 +866,9 @@ impl Item for Editor { let buffer = project_item .downcast::() .context("Project item at stored path was not a buffer")?; - + let pane = pane + .upgrade(&cx) + .ok_or_else(|| anyhow!("pane was dropped"))?; Ok(cx.update(|cx| { cx.add_view(&pane, |cx| { let mut editor = Editor::for_buffer(buffer, Some(project), cx); diff --git a/crates/editor/src/link_go_to_definition.rs b/crates/editor/src/link_go_to_definition.rs index a61b97a683..f943758afb 100644 --- a/crates/editor/src/link_go_to_definition.rs +++ b/crates/editor/src/link_go_to_definition.rs @@ -171,7 +171,7 @@ pub fn show_link_definition( } } - let task = cx.spawn_weak(|this, mut cx| { + let task = cx.spawn(|this, mut cx| { async move { // query the LSP for definition info let definition_request = cx.update(|cx| { diff --git a/crates/editor/src/scroll.rs b/crates/editor/src/scroll.rs index 04b2860c19..63dad8317a 100644 --- a/crates/editor/src/scroll.rs +++ b/crates/editor/src/scroll.rs @@ -245,7 +245,7 @@ impl ScrollManager { } if cx.default_global::().0 { - self.hide_scrollbar_task = Some(cx.spawn_weak(|editor, mut cx| async move { + self.hide_scrollbar_task = Some(cx.spawn(|editor, mut cx| async move { cx.background().timer(SCROLLBAR_SHOW_INTERVAL).await; if let Some(editor) = editor.upgrade(&cx) { editor diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index a1f9002fba..461b751675 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -3262,26 +3262,16 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> { pub fn spawn_labeled(&mut self, task_label: &'static str, f: F) -> Task where - F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, + F: FnOnce(WeakViewHandle, AsyncAppContext) -> Fut, Fut: 'static + Future, S: 'static, { - let handle = self.handle(); + let handle = self.weak_handle(); self.window_context .spawn_labeled(task_label, |cx| f(handle, cx)) } pub fn spawn(&mut self, f: F) -> Task - where - F: FnOnce(ViewHandle, AsyncAppContext) -> Fut, - Fut: 'static + Future, - S: 'static, - { - let handle = self.handle(); - self.window_context.spawn(|cx| f(handle, cx)) - } - - pub fn spawn_weak(&mut self, f: F) -> Task where F: FnOnce(WeakViewHandle, AsyncAppContext) -> Fut, Fut: 'static + Future, @@ -4094,15 +4084,31 @@ impl WeakViewHandle { cx.read_with(|cx| cx.upgrade_view_handle(self)) } + pub fn read_with( + &self, + cx: &impl BorrowAppContext, + read: impl FnOnce(&V, &ViewContext) -> T, + ) -> Result { + cx.read_with(|cx| { + let handle = cx + .upgrade_view_handle(self) + .ok_or_else(|| anyhow!("view {} was dropped", V::ui_name()))?; + cx.read_window(self.window_id, |cx| handle.read_with(cx, read)) + .ok_or_else(|| anyhow!("window was removed")) + }) + } + pub fn update( &self, cx: &mut impl BorrowAppContext, update: impl FnOnce(&mut V, &mut ViewContext) -> T, - ) -> Option { + ) -> Result { cx.update(|cx| { - let handle = cx.upgrade_view_handle(self)?; - + let handle = cx + .upgrade_view_handle(self) + .ok_or_else(|| anyhow!("view {} was dropped", V::ui_name()))?; cx.update_window(self.window_id, |cx| handle.update(cx, update)) + .ok_or_else(|| anyhow!("window was removed")) }) } } diff --git a/crates/gpui/src/elements/tooltip.rs b/crates/gpui/src/elements/tooltip.rs index 4cd924a48c..b65032c73c 100644 --- a/crates/gpui/src/elements/tooltip.rs +++ b/crates/gpui/src/elements/tooltip.rs @@ -99,7 +99,7 @@ impl Tooltip { let mut debounce = state.debounce.borrow_mut(); if debounce.is_none() { - *debounce = Some(cx.spawn_weak({ + *debounce = Some(cx.spawn({ let state = state.clone(); |view, mut cx| async move { cx.background().timer(DEBOUNCE_TIMEOUT).await; diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index 27ddd63e75..c090b97ae8 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/crates/language_selector/src/language_selector.rs @@ -102,7 +102,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_weak(|_, mut cx| async move { + cx.spawn(|_, mut cx| async move { let language = language.await?; let project = project .upgrade(&cx) @@ -138,7 +138,7 @@ impl PickerDelegate for LanguageSelectorDelegate { ) -> gpui::Task<()> { let background = cx.background().clone(); let candidates = self.candidates.clone(); - cx.spawn_weak(|this, mut cx| async move { + cx.spawn(|this, mut cx| async move { let matches = if query.is_empty() { candidates .into_iter() diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 7274962a5b..10be3fe894 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -238,7 +238,7 @@ impl Picker { pub fn update_matches(&mut self, query: String, cx: &mut ViewContext) { let update = self.delegate.update_matches(query, cx); self.matches_updated(cx); - self.pending_update_matches = cx.spawn_weak(|this, mut cx| async move { + self.pending_update_matches = cx.spawn(|this, mut cx| async move { update.await; this.upgrade(&cx)? .update(&mut cx, |this, cx| this.matches_updated(cx)) diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index c730c4d38a..23c1043726 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -117,7 +117,7 @@ impl PickerDelegate for ProjectSymbolsDelegate { }); let symbol = symbol.clone(); let workspace = self.workspace.clone(); - cx.spawn_weak(|_, mut cx| async move { + cx.spawn(|_, mut cx| async move { let buffer = buffer.await?; let workspace = workspace .upgrade(&cx) @@ -161,7 +161,7 @@ impl PickerDelegate for ProjectSymbolsDelegate { let symbols = self .project .update(cx, |project, cx| project.symbols(&query, cx)); - cx.spawn_weak(|this, mut cx| async move { + cx.spawn(|this, mut cx| async move { let symbols = symbols.await.log_err(); if let Some(this) = this.upgrade(&cx) { if let Some(symbols) = symbols { diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index 629a58387c..7486fa2ff5 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -582,7 +582,7 @@ impl BufferSearchBar { let matches = active_searchable_item.find_matches(query, cx); let active_searchable_item = active_searchable_item.downgrade(); - self.pending_search = Some(cx.spawn_weak(|this, mut cx| async move { + self.pending_search = Some(cx.spawn(|this, mut cx| async move { let matches = matches.await; if let Some(this) = this.upgrade(&cx) { this.update(&mut cx, |this, cx| { diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index b7ca3c01c7..16ad527aeb 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -2,13 +2,7 @@ mod persistence; pub mod terminal_button; pub mod terminal_element; -use std::{ - borrow::Cow, - ops::RangeInclusive, - path::{Path, PathBuf}, - time::Duration, -}; - +use anyhow::anyhow; use context_menu::{ContextMenu, ContextMenuItem}; use dirs::home_dir; use gpui::{ @@ -26,6 +20,12 @@ use serde::Deserialize; use settings::{Settings, TerminalBlink, WorkingDirectory}; use smallvec::{smallvec, SmallVec}; use smol::Timer; +use std::{ + borrow::Cow, + ops::RangeInclusive, + path::{Path, PathBuf}, + time::Duration, +}; use terminal::{ alacritty_terminal::{ index::Point, @@ -275,14 +275,11 @@ impl TerminalView { cx.notify(); let epoch = self.next_blink_epoch(); - cx.spawn(|this, mut cx| { - let this = this.downgrade(); - async move { - Timer::after(CURSOR_BLINK_INTERVAL).await; - if let Some(this) = this.upgrade(&cx) { - this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx)) - .log_err(); - } + cx.spawn(|this, mut cx| async move { + Timer::after(CURSOR_BLINK_INTERVAL).await; + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx)) + .log_err(); } }) .detach(); @@ -294,14 +291,11 @@ impl TerminalView { cx.notify(); let epoch = self.next_blink_epoch(); - cx.spawn(|this, mut cx| { - let this = this.downgrade(); - async move { - Timer::after(CURSOR_BLINK_INTERVAL).await; - if let Some(this) = this.upgrade(&cx) { - this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx)) - .log_err(); - } + cx.spawn(|this, mut cx| async move { + Timer::after(CURSOR_BLINK_INTERVAL).await; + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, cx| this.resume_cursor_blinking(epoch, cx)) + .log_err(); } }) .detach(); @@ -646,6 +640,9 @@ impl Item for TerminalView { }) }); + let pane = pane + .upgrade(&cx) + .ok_or_else(|| anyhow!("pane was dropped"))?; cx.update(|cx| { let terminal = project.update(cx, |project, cx| { project.create_terminal(cwd, window_id, cx) diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index ee7066b80f..d02a2dd648 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -163,7 +163,7 @@ impl PickerDelegate for ThemeSelectorDelegate { }) .collect::>(); - cx.spawn_weak(|this, mut cx| async move { + cx.spawn(|this, mut cx| async move { let matches = if query.is_empty() { candidates .into_iter() diff --git a/crates/welcome/src/base_keymap_picker.rs b/crates/welcome/src/base_keymap_picker.rs index 1db340bde9..c2e6c25150 100644 --- a/crates/welcome/src/base_keymap_picker.rs +++ b/crates/welcome/src/base_keymap_picker.rs @@ -81,7 +81,7 @@ impl PickerDelegate for BaseKeymapSelectorDelegate { }) .collect::>(); - cx.spawn_weak(|this, mut cx| async move { + cx.spawn(|this, mut cx| async move { let matches = if query.is_empty() { candidates .into_iter() diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 52c8a60908..6718f0fa5c 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -479,7 +479,7 @@ impl ItemHandle for ViewHandle { }, ); } else { - cx.spawn_weak(|workspace, mut cx| async move { + cx.spawn(|workspace, mut cx| async move { workspace .upgrade(&cx) .ok_or_else(|| anyhow!("workspace was dropped"))? diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index c0fb1a9448..64f6f419c7 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -314,7 +314,7 @@ pub fn init(app_state: Arc, cx: &mut AppContext) { Some(workspace.prepare_to_close(false, cx)) }; - Some(cx.spawn_weak(|_, mut cx| async move { + Some(cx.spawn(|_, mut cx| async move { let window_id_to_replace = if let Some(close_task) = close_task { if !close_task.await? { return Ok(()); @@ -588,7 +588,7 @@ impl DelayedDebouncedEditAction { self.cancel_channel = Some(sender); let previous_task = self.task.take(); - self.task = Some(cx.spawn_weak(|workspace, mut cx| async move { + self.task = Some(cx.spawn(|workspace, mut cx| async move { let mut timer = cx.background().timer(delay).fuse(); if let Some(previous_task) = previous_task { previous_task.await; @@ -733,7 +733,7 @@ impl Workspace { let client = project.read(cx).client(); let mut current_user = user_store.read(cx).watch_current_user(); let mut connection_status = client.status(); - let _observe_current_user = cx.spawn_weak(|this, mut cx| async move { + let _observe_current_user = cx.spawn(|this, mut cx| async move { current_user.recv().await; connection_status.recv().await; let mut stream = @@ -752,7 +752,7 @@ 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_weak(|this, mut cx| async move { + let _apply_leader_updates = cx.spawn(|this, mut cx| async move { while let Some((leader_id, update)) = leader_updates_rx.next().await { let Some(this) = this.upgrade(&cx) else { break }; Self::process_leader_update(this, leader_id, update, &mut cx) @@ -1129,7 +1129,7 @@ impl Workspace { ) -> Option>> { let window_id = cx.window_id(); let prepare = self.prepare_to_close(false, cx); - Some(cx.spawn_weak(|_, mut cx| async move { + Some(cx.spawn(|_, mut cx| async move { if prepare.await? { cx.remove_window(window_id); } @@ -1220,7 +1220,7 @@ impl Workspace { .collect::>(); let project = self.project.clone(); - cx.spawn_weak(|_, mut cx| async move { + cx.spawn(|_, mut cx| async move { for (pane, item) in dirty_items { let (singleton, project_entry_ids) = cx.read(|cx| (item.is_singleton(cx), item.project_entry_ids(cx))); @@ -1975,7 +1975,7 @@ impl Workspace { leader_id: Some(leader_id), }); - Some(cx.spawn_weak(|this, mut cx| async move { + Some(cx.spawn(|this, mut cx| async move { let response = request.await?; if let Some(this) = this.upgrade(&cx) { this.update(&mut cx, |this, _| { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index c035ac07dd..c63a66ebc9 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -503,7 +503,7 @@ fn open_log_file( workspace .with_local_workspace(&app_state.clone(), cx, move |_, cx| { - cx.spawn_weak(|workspace, mut cx| async move { + cx.spawn(|workspace, mut cx| async move { let (old_log, new_log) = futures::join!( app_state.fs.load(&paths::OLD_LOG), app_state.fs.load(&paths::LOG) @@ -558,7 +558,7 @@ fn open_telemetry_log_file( cx: &mut ViewContext, ) { workspace.with_local_workspace(&app_state.clone(), cx, move |_, cx| { - cx.spawn_weak(|workspace, mut cx| async move { + cx.spawn(|workspace, mut cx| async move { let workspace = workspace.upgrade(&cx)?; async fn fetch_log_string(app_state: &Arc) -> Option {