From d03c431f9a14d54de4c2cde0cf1eaa627f32717f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 18 Apr 2023 14:58:57 +0200 Subject: [PATCH] Fix warnings/errors now that `AsyncAppContext::update` returns `Result` --- Cargo.lock | 1 + .../src/activity_indicator.rs | 5 +- crates/auto_update/src/auto_update.rs | 2 +- crates/collab/src/tests/integration_tests.rs | 9 +- crates/collab_ui/src/collab_ui.rs | 2 +- crates/collab_ui/src/contact_finder.rs | 2 +- crates/command_palette/src/command_palette.rs | 4 +- crates/diagnostics/src/diagnostics.rs | 2 +- crates/editor/src/editor.rs | 71 +++++--- crates/editor/src/hover_popover.rs | 4 +- crates/editor/src/items.rs | 14 +- crates/editor/src/link_go_to_definition.rs | 2 +- crates/editor/src/scroll.rs | 10 +- crates/feedback/src/feedback_editor.rs | 16 +- crates/file_finder/src/file_finder.rs | 5 +- crates/journal/src/journal.rs | 54 +++--- crates/language_selector/Cargo.toml | 1 + .../src/language_selector.rs | 37 ++-- crates/picker/src/picker.rs | 31 ++-- crates/project_panel/src/project_panel.rs | 6 +- crates/project_symbols/src/project_symbols.rs | 5 +- crates/recent_projects/src/recent_projects.rs | 31 ++-- crates/search/src/buffer_search.rs | 4 +- crates/terminal_view/src/terminal_view.rs | 4 +- crates/theme_selector/src/theme_selector.rs | 22 ++- crates/welcome/src/base_keymap_picker.rs | 20 ++- crates/workspace/src/item.rs | 41 ++--- crates/workspace/src/pane.rs | 6 +- crates/workspace/src/persistence/model.rs | 17 +- crates/workspace/src/shared_screen.rs | 8 +- crates/workspace/src/workspace.rs | 136 ++++++++------- crates/zed/src/main.rs | 128 ++++++++------ crates/zed/src/zed.rs | 165 +++++++++++------- 33 files changed, 494 insertions(+), 371 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 365f383b48..966b5b49e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3366,6 +3366,7 @@ dependencies = [ "project", "settings", "theme", + "util", "workspace", ] diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index 4637349326..c49348b832 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -2,7 +2,7 @@ use auto_update::{AutoUpdateStatus, AutoUpdater, DismissErrorMessage}; use editor::Editor; use futures::StreamExt; use gpui::{ - actions, + actions, anyhow, elements::*, platform::{CursorStyle, MouseButton}, Action, AppContext, Entity, ModelHandle, View, ViewContext, ViewHandle, @@ -73,11 +73,12 @@ impl ActivityIndicator { status: event, }); cx.notify(); - }); + })?; } else { break; } } + anyhow::Ok(()) }) .detach(); cx.observe(&project, |_, _, cx| cx.notify()).detach(); diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index a12a5dd3a9..b0aa9f1159 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/crates/auto_update/src/auto_update.rs @@ -113,7 +113,7 @@ pub fn notify_of_any_new_update( .read(cx) .set_should_show_update_notification(false, cx) .detach_and_log_err(cx); - }); + })?; } } anyhow::Ok(()) diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index b34b8ee125..5d7e358700 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -6115,7 +6115,8 @@ async fn test_basic_following( .update(cx_a, |workspace, cx| { workspace::Pane::go_back(workspace, None, cx) }) - .await; + .await + .unwrap(); deterministic.run_until_parked(); workspace_b.read_with(cx_b, |workspace, cx| { assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b1.id()); @@ -6125,7 +6126,8 @@ async fn test_basic_following( .update(cx_a, |workspace, cx| { workspace::Pane::go_back(workspace, None, cx) }) - .await; + .await + .unwrap(); deterministic.run_until_parked(); workspace_b.read_with(cx_b, |workspace, cx| { assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b2.id()); @@ -6135,7 +6137,8 @@ async fn test_basic_following( .update(cx_a, |workspace, cx| { workspace::Pane::go_forward(workspace, None, cx) }) - .await; + .await + .unwrap(); deterministic.run_until_parked(); workspace_b.read_with(cx_b, |workspace, cx| { assert_eq!(workspace.active_item(cx).unwrap().id(), editor_b1.id()); diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 7d991f8c94..2902172684 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -126,7 +126,7 @@ fn join_project(action: &JoinProject, app_state: Arc, cx: &mut AppCont } } } - }); + })?; anyhow::Ok(()) }) diff --git a/crates/collab_ui/src/contact_finder.rs b/crates/collab_ui/src/contact_finder.rs index 0ed4f716c7..aaaa701234 100644 --- a/crates/collab_ui/src/contact_finder.rs +++ b/crates/collab_ui/src/contact_finder.rs @@ -67,7 +67,7 @@ impl PickerDelegate for ContactFinder { this.update(&mut cx, |this, cx| { this.potential_contacts = potential_contacts.into(); cx.notify(); - }); + })?; anyhow::Ok(()) } .log_err() diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index 6fc3617132..cecf793825 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -7,6 +7,7 @@ use gpui::{ use picker::{Picker, PickerDelegate}; use settings::Settings; use std::cmp; +use util::ResultExt; use workspace::Workspace; pub fn init(cx: &mut AppContext) { @@ -188,7 +189,8 @@ impl PickerDelegate for CommandPalette { } else { this.selected_ix = cmp::min(this.selected_ix, this.matches.len() - 1); } - }); + }) + .log_err(); }) } diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 90154415d5..42f3bbadf0 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -213,7 +213,7 @@ impl ProjectDiagnosticsEditor { let buffer = project .update(&mut cx, |project, cx| project.open_buffer(path.clone(), cx)) .await?; - this.update(&mut cx, |this, cx| this.populate_excerpts(path, buffer, cx)) + this.update(&mut cx, |this, cx| this.populate_excerpts(path, buffer, cx))?; } Result::<_, anyhow::Error>::Ok(()) } diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 9d1e48be4e..dd4e466b9a 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -20,7 +20,7 @@ mod editor_tests; pub mod test; use aho_corasick::AhoCorasick; -use anyhow::Result; +use anyhow::{anyhow, Result}; use blink_manager::BlinkManager; use clock::ReplicaId; use collections::{BTreeMap, Bound, HashMap, HashSet, VecDeque}; @@ -2397,7 +2397,7 @@ impl Editor { } else if this.hide_context_menu(cx).is_none() { this.update_visible_copilot_suggestion(cx); } - }); + })?; } Ok::<_, anyhow::Error>(()) } @@ -2534,11 +2534,13 @@ impl Editor { prev_task.await; task = this .upgrade(&cx) - .and_then(|this| this.update(&mut cx, |this, _| this.code_actions_task.take())); + .ok_or_else(|| anyhow!("editor dropped"))? + .update(&mut cx, |this, _| this.code_actions_task.take())?; } - if let Some(this) = this.upgrade(&cx) { - this.update(&mut cx, |this, cx| { + this.upgrade(&cx) + .ok_or_else(|| anyhow!("editor dropped"))? + .update(&mut cx, |this, cx| { if this.focused { if let Some((buffer, actions)) = this.available_code_actions.clone() { this.show_context_menu( @@ -2553,8 +2555,8 @@ impl Editor { ); } } - }) - } + })?; + Ok::<_, anyhow::Error>(()) }) .detach_and_log_err(cx); @@ -2666,7 +2668,7 @@ impl Editor { cx, ); }); - }); + })?; Ok(()) } @@ -2697,6 +2699,7 @@ impl Editor { }); cx.notify(); }) + .log_err(); } })); None @@ -2786,7 +2789,8 @@ impl Editor { cx, ); cx.notify(); - }); + }) + .log_err(); } })); None @@ -2823,17 +2827,19 @@ impl Editor { let mut completions = Vec::new(); completions.extend(completion.log_err().into_iter().flatten()); completions.extend(completions_cycling.log_err().into_iter().flatten()); - this.upgrade(&cx)?.update(&mut cx, |this, cx| { - if !completions.is_empty() { - this.copilot_state.completions.clear(); - this.copilot_state.active_completion_index = 0; - this.copilot_state.excerpt_id = Some(cursor.excerpt_id); - for completion in completions { - this.copilot_state.push_completion(completion); + this.upgrade(&cx)? + .update(&mut cx, |this, cx| { + if !completions.is_empty() { + this.copilot_state.completions.clear(); + this.copilot_state.active_completion_index = 0; + this.copilot_state.excerpt_id = Some(cursor.excerpt_id); + for completion in completions { + this.copilot_state.push_completion(completion); + } + this.update_visible_copilot_suggestion(cx); } - this.update_visible_copilot_suggestion(cx); - } - }); + }) + .log_err()?; Some(()) }); @@ -5416,7 +5422,7 @@ impl Editor { let definitions = definitions.await?; workspace.update(&mut cx, |workspace, cx| { Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx); - }); + })?; Ok::<(), anyhow::Error>(()) }) @@ -5517,7 +5523,7 @@ impl Editor { Self::open_locations_in_multibuffer( workspace, locations, replica_id, title, cx, ); - }); + })?; Ok(()) }, @@ -5705,7 +5711,7 @@ impl Editor { editor: rename_editor, block_id, }); - }); + })?; } Ok(()) @@ -5751,7 +5757,7 @@ impl Editor { editor.update(&mut cx, |editor, cx| { editor.refresh_document_highlights(cx); - }); + })?; Ok(()) })) } @@ -6552,9 +6558,16 @@ impl Editor { let position = action.position; let anchor = action.anchor; cx.spawn_weak(|_, mut cx| async move { - let editor = editor.await.log_err()?.downcast::()?; + let editor = editor + .await? + .downcast::() + .ok_or_else(|| anyhow!("opened item was not an editor"))?; editor.update(&mut cx, |editor, cx| { - let buffer = editor.buffer().read(cx).as_singleton()?; + let buffer = editor + .buffer() + .read(cx) + .as_singleton() + .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?; let buffer = buffer.read(cx); let cursor = if buffer.can_resolve(&anchor) { language::ToPoint::to_point(&anchor, buffer) @@ -6568,11 +6581,11 @@ impl Editor { }); editor.nav_history = nav_history; - Some(()) - })?; - Some(()) + anyhow::Ok(()) + })??; + anyhow::Ok(()) }) - .detach() + .detach_and_log_err(cx); } fn marked_text_ranges(&self, cx: &AppContext) -> Option>> { diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index aece05c4c1..0ee55facab 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -208,7 +208,7 @@ fn show_hover( local_diagnostic, primary_diagnostic, }); - }); + })?; } // Construct new hover popover from hover request @@ -254,7 +254,7 @@ fn show_hover( this.hover_state.info_popover = hover_popover; cx.notify(); - }); + })?; } Ok::<_, anyhow::Error>(()) } diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index a39e6fbceb..a6b8665350 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -80,7 +80,9 @@ impl FollowableItem for Editor { }) }); - let editor = editor.unwrap_or_else(|| { + let editor = if let Some(editor) = editor { + editor + } else { pane.update(&mut cx, |_, cx| { let multibuffer = cx.add_model(|cx| { let mut multibuffer; @@ -116,8 +118,8 @@ impl FollowableItem for Editor { }); cx.add_view(|cx| Editor::for_multibuffer(multibuffer, Some(project), cx)) - }) - }); + })? + }; editor.update(&mut cx, |editor, cx| { editor.remote_id = Some(remote_id); @@ -154,7 +156,7 @@ impl FollowableItem for Editor { } anyhow::Ok(()) - })?; + })??; Ok(editor) })) @@ -387,7 +389,7 @@ impl FollowableItem for Editor { offset: vec2f(message.scroll_x, message.scroll_y) }, cx); } - }); + })?; Ok(()) }) } @@ -670,7 +672,7 @@ impl Item for Editor { let transaction = reload_buffers.log_err().await; this.update(&mut cx, |editor, cx| { editor.request_autoscroll(Autoscroll::fit(), cx) - }); + })?; buffer.update(&mut cx, |buffer, _| { if let Some(transaction) = transaction { if !buffer.is_singleton() { diff --git a/crates/editor/src/link_go_to_definition.rs b/crates/editor/src/link_go_to_definition.rs index fa475f168b..a61b97a683 100644 --- a/crates/editor/src/link_go_to_definition.rs +++ b/crates/editor/src/link_go_to_definition.rs @@ -261,7 +261,7 @@ pub fn show_link_definition( hide_link_definition(this, cx); } } - }) + })?; } Ok::<_, anyhow::Error>(()) diff --git a/crates/editor/src/scroll.rs b/crates/editor/src/scroll.rs index 300d4c88f5..04b2860c19 100644 --- a/crates/editor/src/scroll.rs +++ b/crates/editor/src/scroll.rs @@ -248,10 +248,12 @@ impl ScrollManager { self.hide_scrollbar_task = Some(cx.spawn_weak(|editor, mut cx| async move { cx.background().timer(SCROLLBAR_SHOW_INTERVAL).await; if let Some(editor) = editor.upgrade(&cx) { - editor.update(&mut cx, |editor, cx| { - editor.scroll_manager.show_scrollbars = false; - cx.notify(); - }); + editor + .update(&mut cx, |editor, cx| { + editor.scroll_manager.show_scrollbars = false; + cx.notify(); + }) + .log_err(); } })); } else { diff --git a/crates/feedback/src/feedback_editor.rs b/crates/feedback/src/feedback_editor.rs index aae8657911..a8a1031123 100644 --- a/crates/feedback/src/feedback_editor.rs +++ b/crates/feedback/src/feedback_editor.rs @@ -132,9 +132,12 @@ impl FeedbackEditor { if answer == Some(0) { match FeedbackEditor::submit_feedback(&feedback_text, client, specs).await { - Ok(_) => this.update(&mut cx, |_, cx| { - cx.dispatch_action(workspace::CloseActiveItem); - }), + Ok(_) => { + this.update(&mut cx, |_, cx| { + cx.dispatch_action(workspace::CloseActiveItem); + }) + .log_err(); + } Err(error) => { log::error!("{}", error); this.update(&mut cx, |_, cx| { @@ -144,6 +147,7 @@ impl FeedbackEditor { &["OK"], ); }) + .log_err(); } } } @@ -213,10 +217,10 @@ impl FeedbackEditor { .add_view(|cx| FeedbackEditor::new(system_specs, project, buffer, cx)); workspace.add_item(Box::new(feedback_editor), cx); }) - }) - .await; + })? + .await }) - .detach(); + .detach_and_log_err(cx); } } diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index b4c0a0f125..6738ba11b9 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -13,7 +13,7 @@ use std::{ Arc, }, }; -use util::post_inc; +use util::{post_inc, ResultExt}; use workspace::Workspace; pub struct FileFinder { @@ -186,7 +186,8 @@ impl FileFinder { let did_cancel = cancel_flag.load(atomic::Ordering::Relaxed); this.update(&mut cx, |this, cx| { this.set_matches(search_id, did_cancel, query, matches, cx) - }); + }) + .log_err(); }) } diff --git a/crates/journal/src/journal.rs b/crates/journal/src/journal.rs index b74eab4f77..f79f912ab8 100644 --- a/crates/journal/src/journal.rs +++ b/crates/journal/src/journal.rs @@ -7,7 +7,6 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; -use util::TryFutureExt as _; use workspace::AppState; actions!(journal, [NewJournalEntry]); @@ -44,40 +43,37 @@ pub fn new_journal_entry(app_state: Arc, cx: &mut AppContext) { Ok::<_, std::io::Error>((journal_dir, entry_path)) }); - cx.spawn(|mut cx| { - async move { - let (journal_dir, entry_path) = create_entry.await?; - let (workspace, _) = cx - .update(|cx| workspace::open_paths(&[journal_dir], &app_state, cx)) - .await; + cx.spawn(|mut cx| async move { + let (journal_dir, entry_path) = create_entry.await?; + let (workspace, _) = cx + .update(|cx| workspace::open_paths(&[journal_dir], &app_state, cx)) + .await?; - let opened = workspace - .update(&mut cx, |workspace, cx| { - workspace.open_paths(vec![entry_path], true, cx) - }) - .await; + let opened = workspace + .update(&mut cx, |workspace, cx| { + workspace.open_paths(vec![entry_path], true, cx) + })? + .await; - if let Some(Some(Ok(item))) = opened.first() { - if let Some(editor) = item.downcast::() { - editor.update(&mut cx, |editor, cx| { - let len = editor.buffer().read(cx).len(cx); - editor.change_selections(Some(Autoscroll::center()), cx, |s| { - s.select_ranges([len..len]) - }); - if len > 0 { - editor.insert("\n\n", cx); - } - editor.insert(&entry_heading, cx); - editor.insert("\n\n", cx); + if let Some(Some(Ok(item))) = opened.first() { + if let Some(editor) = item.downcast::() { + editor.update(&mut cx, |editor, cx| { + let len = editor.buffer().read(cx).len(cx); + editor.change_selections(Some(Autoscroll::center()), cx, |s| { + s.select_ranges([len..len]) }); - } + if len > 0 { + editor.insert("\n\n", cx); + } + editor.insert(&entry_heading, cx); + editor.insert("\n\n", cx); + })?; } - - anyhow::Ok(()) } - .log_err() + + anyhow::Ok(()) }) - .detach(); + .detach_and_log_err(cx); } fn journal_dir(settings: &Settings) -> Option { diff --git a/crates/language_selector/Cargo.toml b/crates/language_selector/Cargo.toml index 14aa41a465..c77057f42b 100644 --- a/crates/language_selector/Cargo.toml +++ b/crates/language_selector/Cargo.toml @@ -17,5 +17,6 @@ picker = { path = "../picker" } project = { path = "../project" } theme = { path = "../theme" } settings = { path = "../settings" } +util = { path = "../util" } workspace = { path = "../workspace" } anyhow = "1.0" diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index d41a0e312f..c88f46c5d0 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/crates/language_selector/src/language_selector.rs @@ -1,6 +1,7 @@ mod active_buffer_language; pub use active_buffer_language::ActiveBufferLanguage; +use anyhow::anyhow; use editor::Editor; use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use gpui::{ @@ -12,6 +13,7 @@ use picker::{Picker, PickerDelegate}; use project::Project; use settings::Settings; use std::sync::Arc; +use util::ResultExt; use workspace::{AppState, Workspace}; actions!(language_selector, [Toggle]); @@ -140,12 +142,18 @@ impl PickerDelegate for LanguageSelector { if let Some(mat) = self.matches.get(self.selected_index) { let language_name = &self.candidates[mat.candidate_id].string; let language = self.language_registry.language_for_name(language_name); - cx.spawn(|this, mut cx| async move { + let project = self.project.downgrade(); + let buffer = self.buffer.downgrade(); + cx.spawn_weak(|_, mut cx| async move { let language = language.await?; - this.update(&mut cx, |this, cx| { - this.project.update(cx, |project, cx| { - project.set_language_for_buffer(&this.buffer, language, cx); - }); + let project = project + .upgrade(&cx) + .ok_or_else(|| anyhow!("project was dropped"))?; + let buffer = buffer + .upgrade(&cx) + .ok_or_else(|| anyhow!("buffer was dropped"))?; + project.update(&mut cx, |project, cx| { + project.set_language_for_buffer(&buffer, language, cx); }); anyhow::Ok(()) }) @@ -170,7 +178,7 @@ impl PickerDelegate for LanguageSelector { fn update_matches(&mut self, query: String, cx: &mut ViewContext) -> gpui::Task<()> { let background = cx.background().clone(); let candidates = self.candidates.clone(); - cx.spawn(|this, mut cx| async move { + cx.spawn_weak(|this, mut cx| async move { let matches = if query.is_empty() { candidates .into_iter() @@ -194,13 +202,16 @@ impl PickerDelegate for LanguageSelector { .await }; - this.update(&mut cx, |this, cx| { - this.matches = matches; - this.selected_index = this - .selected_index - .min(this.matches.len().saturating_sub(1)); - cx.notify(); - }); + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, cx| { + this.matches = matches; + this.selected_index = this + .selected_index + .min(this.matches.len().saturating_sub(1)); + cx.notify(); + }) + .log_err(); + } }) } diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index afa857b5b4..c17daa891f 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -10,6 +10,7 @@ use gpui::{ use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev}; use parking_lot::Mutex; use std::{cmp, sync::Arc}; +use util::ResultExt; pub struct Picker { delegate: WeakViewHandle, @@ -235,21 +236,23 @@ impl Picker { pub fn update_matches(&mut self, query: String, cx: &mut ViewContext) { if let Some(delegate) = self.delegate.upgrade(cx) { let update = delegate.update(cx, |d, cx| d.update_matches(query, cx)); - cx.spawn(|this, mut cx| async move { + cx.spawn_weak(|this, mut cx| async move { update.await; - this.update(&mut cx, |this, cx| { - if let Some(delegate) = this.delegate.upgrade(cx) { - let delegate = delegate.read(cx); - let index = delegate.selected_index(); - let target = if delegate.center_selection_after_match_updates() { - ScrollTarget::Center(index) - } else { - ScrollTarget::Show(index) - }; - this.list_state.scroll_to(target); - cx.notify(); - } - }); + this.upgrade(&cx)? + .update(&mut cx, |this, cx| { + if let Some(delegate) = this.delegate.upgrade(cx) { + let delegate = delegate.read(cx); + let index = delegate.selected_index(); + let target = if delegate.center_selection_after_match_updates() { + ScrollTarget::Center(index) + } else { + ScrollTarget::Show(index) + }; + this.list_state.scroll_to(target); + cx.notify(); + } + }) + .log_err() }) .detach() } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 2ee884ea52..078bbee67a 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -498,7 +498,7 @@ impl ProjectPanel { this.update(&mut cx, |this, cx| { this.edit_state.take(); cx.notify(); - }); + })?; let new_entry = new_entry?; this.update(&mut cx, |this, cx| { @@ -519,7 +519,7 @@ impl ProjectPanel { ); } cx.notify(); - }); + })?; Ok(()) })) } @@ -655,7 +655,7 @@ impl ProjectPanel { this.project .update(cx, |project, cx| project.delete_entry(entry_id, cx)) .ok_or_else(|| anyhow!("no such entry")) - })? + })?? .await })) } diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index 0189807aa8..62511d9dd7 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -155,7 +155,7 @@ impl ProjectSymbolsView { s.select_ranges([position..position]) }); }); - }); + })?; Ok::<_, anyhow::Error>(()) }) .detach_and_log_err(cx); @@ -225,7 +225,8 @@ impl PickerDelegate for ProjectSymbolsView { this.external_match_candidates = external_match_candidates; this.symbols = symbols; this.filter(&query, cx); - }); + }) + .log_err(); } } }); diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index 520aad150f..81ff50e458 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -10,6 +10,7 @@ use highlighted_workspace_location::HighlightedWorkspaceLocation; use ordered_float::OrderedFloat; use picker::{Picker, PickerDelegate}; use settings::Settings; +use util::ResultExt; use workspace::{ notifications::simple_message_notification::MessageNotification, OpenPaths, Workspace, WorkspaceLocation, WORKSPACE_DB, @@ -57,21 +58,23 @@ impl RecentProjectsView { }) .await; - workspace.update(&mut cx, |workspace, cx| { - if !workspace_locations.is_empty() { - workspace.toggle_modal(cx, |_, cx| { - let view = cx.add_view(|cx| Self::new(workspace_locations, cx)); - cx.subscribe(&view, Self::on_event).detach(); - view - }); - } else { - workspace.show_notification(0, cx, |cx| { - cx.add_view(|_| { - MessageNotification::new_message("No recent projects to open.") + workspace + .update(&mut cx, |workspace, cx| { + if !workspace_locations.is_empty() { + workspace.toggle_modal(cx, |_, cx| { + let view = cx.add_view(|cx| Self::new(workspace_locations, cx)); + cx.subscribe(&view, Self::on_event).detach(); + view + }); + } else { + workspace.show_notification(0, cx, |cx| { + cx.add_view(|_| { + MessageNotification::new_message("No recent projects to open.") + }) }) - }) - } - }); + } + }) + .log_err(); }) .detach(); } diff --git a/crates/search/src/buffer_search.rs b/crates/search/src/buffer_search.rs index f55b044e06..c5a9ac8443 100644 --- a/crates/search/src/buffer_search.rs +++ b/crates/search/src/buffer_search.rs @@ -15,6 +15,7 @@ use project::search::SearchQuery; use serde::Deserialize; use settings::Settings; use std::{any::Any, sync::Arc}; +use util::ResultExt; use workspace::{ item::ItemHandle, searchable::{Direction, SearchEvent, SearchableItemHandle, WeakSearchableItemHandle}, @@ -617,7 +618,8 @@ impl BufferSearchBar { } cx.notify(); } - }); + }) + .log_err(); } })); } diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 3358fdc8d6..f25bbbfcf5 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -279,7 +279,8 @@ impl TerminalView { 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)); + this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx)) + .log_err(); } } }) @@ -298,6 +299,7 @@ impl TerminalView { 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(); } } }) diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 68bc17a576..f03496c82b 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -8,6 +8,7 @@ use settings::{settings_file::SettingsFile, Settings}; use staff_mode::StaffMode; use std::sync::Arc; use theme::{Theme, ThemeMeta, ThemeRegistry}; +use util::ResultExt; use workspace::{AppState, Workspace}; pub struct ThemeSelector { @@ -185,7 +186,7 @@ impl PickerDelegate for ThemeSelector { }) .collect::>(); - cx.spawn(|this, mut cx| async move { + cx.spawn_weak(|this, mut cx| async move { let matches = if query.is_empty() { candidates .into_iter() @@ -209,14 +210,17 @@ impl PickerDelegate for ThemeSelector { .await }; - this.update(&mut cx, |this, cx| { - this.matches = matches; - this.selected_index = this - .selected_index - .min(this.matches.len().saturating_sub(1)); - this.show_selected_theme(cx); - cx.notify(); - }); + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, cx| { + this.matches = matches; + this.selected_index = this + .selected_index + .min(this.matches.len().saturating_sub(1)); + this.show_selected_theme(cx); + cx.notify(); + }) + .log_err(); + } }) } diff --git a/crates/welcome/src/base_keymap_picker.rs b/crates/welcome/src/base_keymap_picker.rs index fd95fe1461..d2a6f6557f 100644 --- a/crates/welcome/src/base_keymap_picker.rs +++ b/crates/welcome/src/base_keymap_picker.rs @@ -6,6 +6,7 @@ use gpui::{ }; use picker::{Picker, PickerDelegate}; use settings::{settings_file::SettingsFile, BaseKeymap, Settings}; +use util::ResultExt; use workspace::Workspace; pub struct BaseKeymapSelector { @@ -109,7 +110,7 @@ impl PickerDelegate for BaseKeymapSelector { }) .collect::>(); - cx.spawn(|this, mut cx| async move { + cx.spawn_weak(|this, mut cx| async move { let matches = if query.is_empty() { candidates .into_iter() @@ -133,13 +134,16 @@ impl PickerDelegate for BaseKeymapSelector { .await }; - this.update(&mut cx, |this, cx| { - this.matches = matches; - this.selected_index = this - .selected_index - .min(this.matches.len().saturating_sub(1)); - cx.notify(); - }); + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, cx| { + this.matches = matches; + this.selected_index = this + .selected_index + .min(this.matches.len().saturating_sub(1)); + cx.notify(); + }) + .log_err(); + } }) } diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 889ee3987b..6a7416849e 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -1,3 +1,17 @@ +use crate::{ + pane, persistence::model::ItemId, searchable::SearchableItemHandle, DelayedDebouncedEditAction, + FollowableItemBuilders, ItemNavHistory, Pane, ToolbarItemLocation, ViewId, Workspace, + WorkspaceId, +}; +use anyhow::{anyhow, Result}; +use client::{proto, Client}; +use gpui::{ + fonts::HighlightStyle, AnyViewHandle, AppContext, Element, ModelHandle, Task, View, + ViewContext, ViewHandle, WeakViewHandle, WindowContext, +}; +use project::{Project, ProjectEntryId, ProjectPath}; +use settings::{Autosave, Settings}; +use smallvec::SmallVec; use std::{ any::{Any, TypeId}, borrow::Cow, @@ -12,24 +26,7 @@ use std::{ }, time::Duration, }; - -use anyhow::Result; -use client::{proto, Client}; -use gpui::{ - fonts::HighlightStyle, AnyViewHandle, AppContext, Element, ModelHandle, Task, View, - ViewContext, ViewHandle, WeakViewHandle, WindowContext, -}; -use project::{Project, ProjectEntryId, ProjectPath}; -use settings::{Autosave, Settings}; -use smallvec::SmallVec; use theme::Theme; -use util::ResultExt; - -use crate::{ - pane, persistence::model::ItemId, searchable::SearchableItemHandle, DelayedDebouncedEditAction, - FollowableItemBuilders, ItemNavHistory, Pane, ToolbarItemLocation, ViewId, Workspace, - WorkspaceId, -}; #[derive(Eq, PartialEq, Hash)] pub enum ItemEvent { @@ -461,18 +458,18 @@ impl ItemHandle for ViewHandle { } else { cx.spawn_weak(|workspace, mut cx| async move { workspace - .upgrade(&cx)? + .upgrade(&cx) + .ok_or_else(|| anyhow!("workspace was dropped"))? .update(&mut cx, |workspace, cx| { item.git_diff_recalc( workspace.project().clone(), cx, ) })? - .await - .log_err()?; - Some(()) + .await?; + anyhow::Ok(()) }) - .detach(); + .detach_and_log_err(cx); } } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 0167157b30..2adc1e0a32 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -540,7 +540,7 @@ impl Pane { .update(&mut cx, |workspace, cx| { Self::navigate_history(workspace, pane, mode, cx) })? - .await; + .await?; } Ok(()) @@ -1014,10 +1014,10 @@ impl Pane { if let Some(item_ix) = pane.items.iter().position(|i| i.id() == item.id()) { pane.remove_item(item_ix, false, cx); } - }); + })?; } - pane.update(&mut cx, |_, cx| cx.notify()); + pane.update(&mut cx, |_, cx| cx.notify())?; Ok(()) }) } diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index ad5e5241d6..1520b7f6a0 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -131,16 +131,21 @@ impl SerializedPaneGroup { )) } SerializedPaneGroup::Pane(serialized_pane) => { - let pane = workspace.update(cx, |workspace, cx| workspace.add_pane(cx))?; + let pane = workspace + .update(cx, |workspace, cx| workspace.add_pane(cx)) + .log_err()?; let active = serialized_pane.active; serialized_pane .deserialize_to(project, &pane, workspace_id, workspace, cx) - .await; + .await + .log_err()?; if pane.read_with(cx, |pane, _| pane.items_len() != 0) { Some((Member::Pane(pane.clone()), active.then(|| pane))) } else { - workspace.update(cx, |workspace, cx| workspace.remove_pane(pane, cx)); + workspace + .update(cx, |workspace, cx| workspace.remove_pane(pane, cx)) + .log_err()?; None } } @@ -166,7 +171,7 @@ impl SerializedPane { workspace_id: WorkspaceId, workspace: &ViewHandle, cx: &mut AsyncAppContext, - ) -> Option<()> { + ) -> Result<()> { let mut active_item_index = None; for (index, item) in self.children.iter().enumerate() { let project = project.clone(); @@ -193,7 +198,7 @@ impl SerializedPane { if let Some(item_handle) = item_handle { workspace.update(cx, |workspace, cx| { Pane::add_item(workspace, &pane_handle, item_handle, false, false, None, cx); - }); + })?; } if item.active { @@ -207,7 +212,7 @@ impl SerializedPane { })?; } - Some(()) + anyhow::Ok(()) } } diff --git a/crates/workspace/src/shared_screen.rs b/crates/workspace/src/shared_screen.rs index 8219149ae6..17f7c061c5 100644 --- a/crates/workspace/src/shared_screen.rs +++ b/crates/workspace/src/shared_screen.rs @@ -2,6 +2,7 @@ use crate::{ item::{Item, ItemEvent}, ItemNavHistory, Pane, WorkspaceId, }; +use anyhow::Result; use call::participant::{Frame, RemoteVideoTrack}; use client::{proto::PeerId, User}; use futures::StreamExt; @@ -25,7 +26,7 @@ pub struct SharedScreen { pub peer_id: PeerId, user: Arc, nav_history: Option, - _maintain_frame: Task<()>, + _maintain_frame: Task>, } impl SharedScreen { @@ -47,9 +48,10 @@ impl SharedScreen { this.update(&mut cx, |this, cx| { this.frame = Some(frame); cx.notify(); - }) + })?; } - this.update(&mut cx, |_, cx| cx.emit(Event::Close)); + this.update(&mut cx, |_, cx| cx.emit(Event::Close))?; + Ok(()) }), } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 3cc9beb160..308db5dc6c 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -306,7 +306,7 @@ pub fn init(app_state: Arc, cx: &mut AppContext) { let can_close = close.await?; if can_close { cx.update(|cx| open_paths(&action.paths, &app_state, cx)) - .await; + .await?; } Ok(()) })) @@ -583,10 +583,12 @@ impl DelayedDebouncedEditAction { } if let Some(workspace) = workspace.upgrade(&cx) { - workspace + if let Some(result) = workspace .update(&mut cx, |workspace, cx| (f)(workspace, cx)) - .await - .log_err(); + .log_err() + { + result.await.log_err(); + } } })); } @@ -627,7 +629,7 @@ pub struct Workspace { background_actions: BackgroundActions, _window_subscriptions: [Subscription; 3], _apply_leader_updates: Task>, - _observe_current_user: Task<()>, + _observe_current_user: Task>, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -723,9 +725,10 @@ impl Workspace { while stream.recv().await.is_some() { if let Some(this) = this.upgrade(&cx) { - this.update(&mut cx, |_, cx| cx.notify()); + this.update(&mut cx, |_, cx| cx.notify())?; } } + anyhow::Ok(()) }); let handle = cx.handle(); @@ -979,6 +982,7 @@ impl Workspace { .update(&mut cx, |workspace, cx| { workspace.open_path(project_path, None, true, cx) }) + .log_err()? .await, ) } else { @@ -1040,13 +1044,13 @@ impl Workspace { app_state: &Arc, cx: &mut ViewContext, callback: F, - ) -> Task + ) -> Task> where T: 'static, F: 'static + FnOnce(&mut Workspace, &mut ViewContext) -> T, { if self.project.read(cx).is_local() { - Task::Ready(Some(callback(self, cx))) + Task::Ready(Some(Ok(callback(self, cx)))) } else { let task = Self::new_local(Vec::new(), app_state.clone(), cx); cx.spawn(|_vh, mut cx| async move { @@ -1097,13 +1101,11 @@ impl Workspace { _: &CloseWindow, cx: &mut ViewContext, ) -> Option>> { + let window_id = cx.window_id(); let prepare = self.prepare_to_close(false, cx); - Some(cx.spawn(|this, mut cx| async move { + Some(cx.spawn_weak(|_, mut cx| async move { if prepare.await? { - this.update(&mut cx, |_, cx| { - let window_id = cx.window_id(); - cx.remove_window(window_id); - }); + cx.remove_window(window_id); } Ok(()) })) @@ -1155,7 +1157,7 @@ impl Workspace { } Ok(this - .update(&mut cx, |this, cx| this.save_all_internal(true, cx)) + .update(&mut cx, |this, cx| this.save_all_internal(true, cx))? .await?) }) } @@ -1233,13 +1235,16 @@ impl Workspace { cx.spawn(|this, mut cx| async move { let mut project_paths = Vec::new(); for path in &abs_paths { - project_paths.push( - this.update(&mut cx, |this, cx| { + if let Some(project_path) = this + .update(&mut cx, |this, cx| { Workspace::project_path_for_path(this.project.clone(), path, visible, cx) }) - .await - .log_err(), - ); + .log_err() + { + project_paths.push(project_path.await.log_err()); + } else { + project_paths.push(None); + } } let tasks = abs_paths @@ -1257,6 +1262,7 @@ impl Workspace { this.update(&mut cx, |this, cx| { this.open_path(project_path, None, true, cx) }) + .log_err()? .await, ) } else { @@ -1280,14 +1286,15 @@ impl Workspace { cx.spawn(|this, mut cx| async move { if let Some(paths) = paths.recv().await.flatten() { let results = this - .update(&mut cx, |this, cx| this.open_paths(paths, true, cx)) + .update(&mut cx, |this, cx| this.open_paths(paths, true, cx))? .await; for result in results.into_iter().flatten() { result.log_err(); } } + anyhow::Ok(()) }) - .detach(); + .detach_and_log_err(cx); } fn remove_folder_from_project( @@ -1406,7 +1413,7 @@ impl Workspace { cx.spawn(|this, mut cx| async move { let answer = answer.recv().await; if answer == Some(0) { - this.update(&mut cx, |this, cx| item.save(this.project.clone(), cx)) + this.update(&mut cx, |this, cx| item.save(this.project.clone(), cx))? .await?; } Ok(()) @@ -1423,7 +1430,7 @@ impl Workspace { let mut abs_path = cx.prompt_for_new_path(&start_abs_path); cx.spawn(|this, mut cx| async move { if let Some(abs_path) = abs_path.recv().await.flatten() { - this.update(&mut cx, |_, cx| item.save_as(project, abs_path, cx)) + this.update(&mut cx, |_, cx| item.save_as(project, abs_path, cx))? .await?; } Ok(()) @@ -1588,14 +1595,7 @@ impl Workspace { .upgrade(&cx) .ok_or_else(|| anyhow!("pane was closed"))?; this.update(&mut cx, |this, cx| { - Ok(Pane::open_item( - this, - pane, - project_entry_id, - focus_item, - cx, - build_item, - )) + Pane::open_item(this, pane, project_entry_id, focus_item, cx, build_item) }) }) } @@ -1958,7 +1958,7 @@ impl Workspace { None }; Ok::<_, anyhow::Error>(()) - })?; + })??; Self::add_views_from_leader( this.clone(), leader_id, @@ -1967,7 +1967,7 @@ impl Workspace { &mut cx, ) .await?; - this.update(&mut cx, |this, cx| this.leader_updated(leader_id, cx)); + this.update(&mut cx, |this, cx| this.leader_updated(leader_id, cx))?; } Ok(()) })) @@ -2245,7 +2245,7 @@ impl Workspace { }) .collect(), }) - }) + })? } async fn handle_unfollow( @@ -2260,7 +2260,7 @@ impl Workspace { .remove(&envelope.original_sender_id()?); cx.notify(); Ok(()) - }) + })? } async fn handle_update_followers( @@ -2297,7 +2297,7 @@ impl Workspace { } } anyhow::Ok(()) - })?; + })??; } proto::update_followers::Variant::UpdateView(update_view) => { let variant = update_view @@ -2318,7 +2318,7 @@ impl Workspace { } } anyhow::Ok(()) - })?; + })??; try_join_all(tasks).await.log_err(); } proto::update_followers::Variant::CreateView(view) => { @@ -2333,7 +2333,7 @@ impl Workspace { Self::add_views_from_leader(this.clone(), leader_id, panes, vec![view], cx).await?; } } - this.update(cx, |this, cx| this.leader_updated(leader_id, cx)); + this.update(cx, |this, cx| this.leader_updated(leader_id, cx))?; Ok(()) } @@ -2403,7 +2403,7 @@ impl Workspace { } Some(()) - }); + })?; } Ok(()) } @@ -2685,7 +2685,7 @@ impl Workspace { &workspace, &mut cx, ) - .await; + .await?; // Traverse the splits tree and add to things let center_group = serialized_workspace @@ -2737,13 +2737,14 @@ impl Workspace { }); cx.notify(); - }); + })?; // Serialize ourself to make sure our timestamps and any pane / item changes are replicated workspace.read_with(&cx, |workspace, cx| workspace.serialize_workspace(cx)) } + anyhow::Ok(()) }) - .detach(); + .detach_and_log_err(cx); } #[cfg(any(test, feature = "test-support"))] @@ -2753,8 +2754,8 @@ impl Workspace { } fn notify_if_database_failed(workspace: &ViewHandle, cx: &mut AsyncAppContext) { - if (*db::ALL_FILE_DB_FAILED).load(std::sync::atomic::Ordering::Acquire) { - workspace.update(cx, |workspace, cx| { + workspace.update(cx, |workspace, cx| { + if (*db::ALL_FILE_DB_FAILED).load(std::sync::atomic::Ordering::Acquire) { workspace.show_notification_once(0, cx, |cx| { cx.add_view(|_| { MessageNotification::new( @@ -2766,11 +2767,9 @@ fn notify_if_database_failed(workspace: &ViewHandle, cx: &mut AsyncAp ) }) }); - }); - } else { - let backup_path = (*db::BACKUP_DB_PATH).read(); - if let Some(backup_path) = &*backup_path { - workspace.update(cx, |workspace, cx| { + } else { + let backup_path = (*db::BACKUP_DB_PATH).read(); + if let Some(backup_path) = &*backup_path { workspace.show_notification_once(0, cx, |cx| { cx.add_view(|_| { let backup_path = backup_path.to_string_lossy(); @@ -2788,9 +2787,9 @@ fn notify_if_database_failed(workspace: &ViewHandle, cx: &mut AsyncAp ) }) }); - }); + } } - } + }).log_err(); } impl Entity for Workspace { @@ -3017,10 +3016,12 @@ pub fn open_paths( abs_paths: &[PathBuf], app_state: &Arc, cx: &mut AppContext, -) -> Task<( - ViewHandle, - Vec, anyhow::Error>>>, -)> { +) -> Task< + Result<( + ViewHandle, + Vec, anyhow::Error>>>, + )>, +> { log::info!("open paths {:?}", abs_paths); // Open paths in existing workspace if possible @@ -3031,14 +3032,14 @@ pub fn open_paths( let abs_paths = abs_paths.to_vec(); cx.spawn(|mut cx| async move { if let Some(existing) = existing { - ( + Ok(( existing.clone(), existing .update(&mut cx, |workspace, cx| { workspace.open_paths(abs_paths, true, cx) - }) + })? .await, - ) + )) } else { let contains_directory = futures::future::join_all(abs_paths.iter().map(|path| app_state.fs.is_file(path))) @@ -3055,9 +3056,9 @@ pub fn open_paths( if contains_directory { workspace.toggle_sidebar(SidebarSide::Left, cx); } - }); + })?; - (workspace, items) + anyhow::Ok((workspace, items)) }) }) .await @@ -3074,11 +3075,13 @@ pub fn open_new( cx.spawn(|mut cx| async move { let (workspace, opened_paths) = task.await; - workspace.update(&mut cx, |workspace, cx| { - if opened_paths.is_empty() { - init(workspace, cx) - } - }) + workspace + .update(&mut cx, |workspace, cx| { + if opened_paths.is_empty() { + init(workspace, cx) + } + }) + .log_err(); }) } @@ -3702,7 +3705,8 @@ mod tests { .update(cx, |workspace, cx| { Pane::go_back(workspace, Some(pane.clone()), cx) }) - .await; + .await + .unwrap(); assert_eq!(*toolbar_notify_count.borrow(), 3); pane.read_with(cx, |pane, _| { diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index ec678eb23f..a7db5dd8c8 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -606,71 +606,87 @@ async fn handle_cli_connection( } else { paths }; - let (workspace, items) = cx - .update(|cx| workspace::open_paths(&paths, &app_state, cx)) - .await; let mut errored = false; - let mut item_release_futures = Vec::new(); - cx.update(|cx| { - for (item, path) in items.into_iter().zip(&paths) { - match item { - Some(Ok(item)) => { - let released = oneshot::channel(); - item.on_release( - cx, - Box::new(move |_| { - let _ = released.0.send(()); - }), - ) - .detach(); - item_release_futures.push(released.1); + match cx + .update(|cx| workspace::open_paths(&paths, &app_state, cx)) + .await + { + Ok((workspace, items)) => { + let mut item_release_futures = Vec::new(); + cx.update(|cx| { + for (item, path) in items.into_iter().zip(&paths) { + match item { + Some(Ok(item)) => { + let released = oneshot::channel(); + item.on_release( + cx, + Box::new(move |_| { + let _ = released.0.send(()); + }), + ) + .detach(); + item_release_futures.push(released.1); + } + Some(Err(err)) => { + responses + .send(CliResponse::Stderr { + message: format!( + "error opening {:?}: {}", + path, err + ), + }) + .log_err(); + errored = true; + } + None => {} + } } - Some(Err(err)) => { - responses - .send(CliResponse::Stderr { - message: format!("error opening {:?}: {}", path, err), - }) - .log_err(); - errored = true; + }); + + if wait { + let background = cx.background(); + let wait = async move { + if paths.is_empty() { + let (done_tx, done_rx) = oneshot::channel(); + let _subscription = cx.update(|cx| { + cx.observe_release(&workspace, move |_, _| { + let _ = done_tx.send(()); + }) + }); + drop(workspace); + let _ = done_rx.await; + } else { + let _ = + futures::future::try_join_all(item_release_futures).await; + }; } - None => {} - } - } - }); + .fuse(); + futures::pin_mut!(wait); - if wait { - let background = cx.background(); - let wait = async move { - if paths.is_empty() { - let (done_tx, done_rx) = oneshot::channel(); - let _subscription = cx.update(|cx| { - cx.observe_release(&workspace, move |_, _| { - let _ = done_tx.send(()); - }) - }); - drop(workspace); - let _ = done_rx.await; - } else { - let _ = futures::future::try_join_all(item_release_futures).await; - }; - } - .fuse(); - futures::pin_mut!(wait); - - loop { - // Repeatedly check if CLI is still open to avoid wasting resources - // waiting for files or workspaces to close. - let mut timer = background.timer(Duration::from_secs(1)).fuse(); - futures::select_biased! { - _ = wait => break, - _ = timer => { - if responses.send(CliResponse::Ping).is_err() { - break; + loop { + // Repeatedly check if CLI is still open to avoid wasting resources + // waiting for files or workspaces to close. + let mut timer = background.timer(Duration::from_secs(1)).fuse(); + futures::select_biased! { + _ = wait => break, + _ = timer => { + if responses.send(CliResponse::Ping).is_err() { + break; + } + } } } } } + Err(error) => { + errored = true; + responses + .send(CliResponse::Stderr { + message: format!("error opening {:?}: {}", paths, error), + }) + .log_err(); + } } responses diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 1823db9ae2..c8f1f41c02 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -247,10 +247,10 @@ pub fn init(app_state: &Arc, cx: &mut gpui::AppContext) { cx, ); }) - }) - .await; + })? + .await }) - .detach(); + .detach_and_log_err(cx); } }); cx.add_action( @@ -399,7 +399,7 @@ fn restart(_: &Restart, cx: &mut gpui::AppContext) { if !workspace .update(&mut cx, |workspace, cx| { workspace.prepare_to_close(true, cx) - }) + })? .await? { return Ok(()); @@ -444,7 +444,7 @@ fn quit(_: &Quit, cx: &mut gpui::AppContext) { if !workspace .update(&mut cx, |workspace, cx| { workspace.prepare_to_close(true, cx) - }) + })? .await? { return Ok(()); @@ -481,8 +481,8 @@ fn open_config_file( workspace.with_local_workspace(&app_state, cx, |workspace, cx| { workspace.open_paths(vec![path.to_path_buf()], false, cx) }) - }) - .await + })? + .await? .await; Ok::<_, anyhow::Error>(()) }) @@ -521,25 +521,25 @@ fn open_log_file( .flat_map(|line| [line, "\n"]) .collect::(); - workspace.update(&mut cx, |workspace, cx| { - let project = workspace.project().clone(); - let buffer = project - .update(cx, |project, cx| project.create_buffer("", None, cx)) - .expect("creating buffers on a local workspace always succeeds"); - buffer.update(cx, |buffer, cx| buffer.edit([(0..0, log)], None, cx)); + workspace + .update(&mut cx, |workspace, cx| { + let project = workspace.project().clone(); + let buffer = project + .update(cx, |project, cx| project.create_buffer("", None, cx)) + .expect("creating buffers on a local workspace always succeeds"); + buffer.update(cx, |buffer, cx| buffer.edit([(0..0, log)], None, cx)); - let buffer = cx.add_model(|cx| { - MultiBuffer::singleton(buffer, cx).with_title("Log".into()) - }); - workspace.add_item( - Box::new( - cx.add_view(|cx| { + let buffer = cx.add_model(|cx| { + MultiBuffer::singleton(buffer, cx).with_title("Log".into()) + }); + workspace.add_item( + Box::new(cx.add_view(|cx| { Editor::for_multibuffer(buffer, Some(project), cx) - }), - ), - cx, - ); - }); + })), + cx, + ); + }) + .log_err(); } }) .detach(); @@ -601,7 +601,7 @@ fn open_telemetry_log_file( Box::new(cx.add_view(|cx| Editor::for_multibuffer(buffer, Some(project), cx))), cx, ); - }); + }).log_err()?; Some(()) }) @@ -642,10 +642,10 @@ fn open_bundled_file( cx, ); }) - }) - .await; + })? + .await }) - .detach(); + .detach_and_log_err(cx); } #[cfg(test)] @@ -705,11 +705,13 @@ mod tests { cx, ) }) - .await; + .await + .unwrap(); assert_eq!(cx.window_ids().len(), 1); cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, cx)) - .await; + .await + .unwrap(); assert_eq!(cx.window_ids().len(), 1); let workspace_1 = cx .read_window(cx.window_ids()[0], |cx| cx.root_view().clone()) @@ -729,7 +731,8 @@ mod tests { cx, ) }) - .await; + .await + .unwrap(); assert_eq!(cx.window_ids().len(), 2); // Replace existing windows @@ -741,7 +744,8 @@ mod tests { cx, ) }) - .await; + .await + .unwrap(); assert_eq!(cx.window_ids().len(), 2); cx.read_window(window_id, |cx| { let workspace = cx.root_view().clone().downcast::().unwrap(); @@ -768,7 +772,8 @@ mod tests { .await; cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, cx)) - .await; + .await + .unwrap(); assert_eq!(cx.window_ids().len(), 1); // When opening the workspace, the window is not in a edited state. @@ -810,7 +815,8 @@ mod tests { // Opening the buffer again doesn't impact the window's edited state. cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, cx)) - .await; + .await + .unwrap(); let editor = workspace.read_with(cx, |workspace, cx| { workspace .active_item(cx) @@ -1475,7 +1481,8 @@ mod tests { workspace .update(cx, |w, cx| Pane::go_back(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file3.clone(), DisplayPoint::new(0, 0), 0.) @@ -1483,7 +1490,8 @@ mod tests { workspace .update(cx, |w, cx| Pane::go_back(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file2.clone(), DisplayPoint::new(0, 0), 0.) @@ -1491,7 +1499,8 @@ mod tests { workspace .update(cx, |w, cx| Pane::go_back(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file1.clone(), DisplayPoint::new(10, 0), 0.) @@ -1499,7 +1508,8 @@ mod tests { workspace .update(cx, |w, cx| Pane::go_back(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file1.clone(), DisplayPoint::new(0, 0), 0.) @@ -1508,7 +1518,8 @@ mod tests { // Go back one more time and ensure we don't navigate past the first item in the history. workspace .update(cx, |w, cx| Pane::go_back(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file1.clone(), DisplayPoint::new(0, 0), 0.) @@ -1516,7 +1527,8 @@ mod tests { workspace .update(cx, |w, cx| Pane::go_forward(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file1.clone(), DisplayPoint::new(10, 0), 0.) @@ -1524,7 +1536,8 @@ mod tests { workspace .update(cx, |w, cx| Pane::go_forward(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file2.clone(), DisplayPoint::new(0, 0), 0.) @@ -1542,7 +1555,8 @@ mod tests { .unwrap(); workspace .update(cx, |w, cx| Pane::go_forward(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file3.clone(), DisplayPoint::new(0, 0), 0.) @@ -1550,7 +1564,8 @@ mod tests { workspace .update(cx, |w, cx| Pane::go_forward(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file3.clone(), DisplayPoint::new(16, 0), 12.5) @@ -1558,7 +1573,8 @@ mod tests { workspace .update(cx, |w, cx| Pane::go_back(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file3.clone(), DisplayPoint::new(0, 0), 0.) @@ -1580,14 +1596,16 @@ mod tests { .unwrap(); workspace .update(cx, |w, cx| Pane::go_back(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file1.clone(), DisplayPoint::new(10, 0), 0.) ); workspace .update(cx, |w, cx| Pane::go_forward(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file3.clone(), DisplayPoint::new(0, 0), 0.) @@ -1630,14 +1648,16 @@ mod tests { }); workspace .update(cx, |w, cx| Pane::go_back(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file1.clone(), DisplayPoint::new(2, 0), 0.) ); workspace .update(cx, |w, cx| Pane::go_back(w, None, cx)) - .await; + .await + .unwrap(); assert_eq!( active_location(&workspace, cx), (file1.clone(), DisplayPoint::new(3, 0), 0.) @@ -1751,61 +1771,84 @@ mod tests { // Reopen all the closed items, ensuring they are reopened in the same order // in which they were closed. - workspace.update(cx, Pane::reopen_closed_item).await; + workspace + .update(cx, Pane::reopen_closed_item) + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file3.clone())); - workspace.update(cx, Pane::reopen_closed_item).await; + workspace + .update(cx, Pane::reopen_closed_item) + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file2.clone())); - workspace.update(cx, Pane::reopen_closed_item).await; + workspace + .update(cx, Pane::reopen_closed_item) + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file4.clone())); - workspace.update(cx, Pane::reopen_closed_item).await; + workspace + .update(cx, Pane::reopen_closed_item) + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file1.clone())); // Reopening past the last closed item is a no-op. - workspace.update(cx, Pane::reopen_closed_item).await; + workspace + .update(cx, Pane::reopen_closed_item) + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file1.clone())); // Reopening closed items doesn't interfere with navigation history. workspace .update(cx, |workspace, cx| Pane::go_back(workspace, None, cx)) - .await; + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file4.clone())); workspace .update(cx, |workspace, cx| Pane::go_back(workspace, None, cx)) - .await; + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file2.clone())); workspace .update(cx, |workspace, cx| Pane::go_back(workspace, None, cx)) - .await; + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file3.clone())); workspace .update(cx, |workspace, cx| Pane::go_back(workspace, None, cx)) - .await; + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file4.clone())); workspace .update(cx, |workspace, cx| Pane::go_back(workspace, None, cx)) - .await; + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file3.clone())); workspace .update(cx, |workspace, cx| Pane::go_back(workspace, None, cx)) - .await; + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file2.clone())); workspace .update(cx, |workspace, cx| Pane::go_back(workspace, None, cx)) - .await; + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file1.clone())); workspace .update(cx, |workspace, cx| Pane::go_back(workspace, None, cx)) - .await; + .await + .unwrap(); assert_eq!(active_path(&workspace, cx), Some(file1.clone())); fn active_path(