Tidy up single-file worktrees' opening errors (#44455)

Kirill Bulatov created

Part of https://github.com/zed-industries/zed/issues/44370

Also log when fail to open the project item.

Release Notes:

- N/A

Change summary

crates/project/src/buffer_store.rs        |  18 +++
crates/project/src/invalid_item_view.rs   | 118 -------------------------
crates/workspace/src/invalid_item_view.rs |   1 
crates/workspace/src/workspace.rs         |   1 
4 files changed, 17 insertions(+), 121 deletions(-)

Detailed changes

crates/project/src/buffer_store.rs 🔗

@@ -620,9 +620,21 @@ impl LocalBufferStore {
         let load_file = worktree.update(cx, |worktree, cx| worktree.load_file(path.as_ref(), cx));
         cx.spawn(async move |this, cx| {
             let path = path.clone();
-            let buffer = match load_file.await.with_context(|| {
-                format!("Could not open path: {}", path.display(PathStyle::local()))
-            }) {
+            let single_file_path = cx.update(|cx| {
+                if worktree.read(cx).is_single_file() {
+                    Some(worktree.read(cx).abs_path())
+                } else {
+                    None
+                }
+            })?;
+            let path_string = single_file_path
+                .as_ref()
+                .map(|path| path.to_string_lossy())
+                .unwrap_or_else(|| path.display(PathStyle::local()));
+            let buffer = match load_file
+                .await
+                .with_context(|| format!("Opening path \"{path_string}\""))
+            {
                 Ok(loaded) => {
                     let reservation = cx.reserve_entity::<Buffer>()?;
                     let buffer_id = BufferId::from(reservation.entity_id().as_non_zero_u64());

crates/project/src/invalid_item_view.rs 🔗

@@ -1,118 +0,0 @@
-use std::{path::Path, sync::Arc};
-
-use gpui::{EventEmitter, FocusHandle, Focusable};
-use ui::{
-    App, Button, ButtonCommon, ButtonStyle, Clickable, Context, FluentBuilder, InteractiveElement,
-    KeyBinding, Label, LabelCommon, LabelSize, ParentElement, Render, SharedString, Styled as _,
-    Window, h_flex, v_flex,
-};
-use zed_actions::workspace::OpenWithSystem;
-
-use crate::Item;
-
-/// A view to display when a certain buffer fails to open.
-#[derive(Debug)]
-pub struct InvalidItemView {
-    /// Which path was attempted to open.
-    pub abs_path: Arc<Path>,
-    /// An error message, happened when opening the buffer.
-    pub error: SharedString,
-    is_local: bool,
-    focus_handle: FocusHandle,
-}
-
-impl InvalidItemView {
-    pub fn new(
-        abs_path: &Path,
-        is_local: bool,
-        e: &anyhow::Error,
-        _: &mut Window,
-        cx: &mut App,
-    ) -> Self {
-        Self {
-            is_local,
-            abs_path: Arc::from(abs_path),
-            error: format!("{}", e.root_cause()).into(),
-            focus_handle: cx.focus_handle(),
-        }
-    }
-}
-
-impl Item for InvalidItemView {
-    type Event = ();
-
-    fn tab_content_text(&self, mut detail: usize, _: &App) -> SharedString {
-        // Ensure we always render at least the filename.
-        detail += 1;
-
-        let path = self.abs_path.as_ref();
-
-        let mut prefix = path;
-        while detail > 0 {
-            if let Some(parent) = prefix.parent() {
-                prefix = parent;
-                detail -= 1;
-            } else {
-                break;
-            }
-        }
-
-        let path = if detail > 0 {
-            path
-        } else {
-            path.strip_prefix(prefix).unwrap_or(path)
-        };
-
-        SharedString::new(path.to_string_lossy())
-    }
-}
-
-impl EventEmitter<()> for InvalidItemView {}
-
-impl Focusable for InvalidItemView {
-    fn focus_handle(&self, _: &App) -> FocusHandle {
-        self.focus_handle.clone()
-    }
-}
-
-impl Render for InvalidItemView {
-    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl gpui::IntoElement {
-        let abs_path = self.abs_path.clone();
-        v_flex()
-            .size_full()
-            .track_focus(&self.focus_handle(cx))
-            .flex_none()
-            .justify_center()
-            .overflow_hidden()
-            .key_context("InvalidBuffer")
-            .child(
-                h_flex().size_full().justify_center().child(
-                    v_flex()
-                        .justify_center()
-                        .gap_2()
-                        .child(h_flex().justify_center().child("Could not open file"))
-                        .child(
-                            h_flex()
-                                .justify_center()
-                                .child(Label::new(self.error.clone()).size(LabelSize::Small)),
-                        )
-                        .when(self.is_local, |contents| {
-                            contents.child(
-                                h_flex().justify_center().child(
-                                    Button::new("open-with-system", "Open in Default App")
-                                        .on_click(move |_, _, cx| {
-                                            cx.open_with_system(&abs_path);
-                                        })
-                                        .style(ButtonStyle::Outlined)
-                                        .key_binding(KeyBinding::for_action(
-                                            &OpenWithSystem,
-                                            window,
-                                            cx,
-                                        )),
-                                ),
-                            )
-                        }),
-                ),
-            )
-    }
-}

crates/workspace/src/invalid_item_view.rs 🔗

@@ -11,6 +11,7 @@ use zed_actions::workspace::OpenWithSystem;
 use crate::Item;
 
 /// A view to display when a certain buffer/image/other item fails to open.
+#[derive(Debug)]
 pub struct InvalidItemView {
     /// Which path was attempted to open.
     pub abs_path: Arc<Path>,

crates/workspace/src/workspace.rs 🔗

@@ -675,6 +675,7 @@ impl ProjectItemRegistry {
                             Ok((project_entry_id, build_workspace_item))
                         }
                         Err(e) => {
+                            log::warn!("Failed to open a project item: {e:#}");
                             if e.error_code() == ErrorCode::Internal {
                                 if let Some(abs_path) =
                                     entry_abs_path.as_deref().filter(|_| is_file)