invalid_buffer_view.rs

  1use std::{path::Path, sync::Arc};
  2
  3use gpui::{EventEmitter, FocusHandle, Focusable};
  4use ui::{
  5    App, Button, ButtonCommon, ButtonStyle, Clickable, Context, FluentBuilder, InteractiveElement,
  6    KeyBinding, ParentElement, Render, SharedString, Styled as _, Window, h_flex, v_flex,
  7};
  8use zed_actions::workspace::OpenWithSystem;
  9
 10use crate::Item;
 11
 12/// A view to display when a certain buffer fails to open.
 13pub struct InvalidBufferView {
 14    /// Which path was attempted to open.
 15    pub abs_path: Arc<Path>,
 16    /// An error message, happened when opening the buffer.
 17    pub error: SharedString,
 18    is_local: bool,
 19    focus_handle: FocusHandle,
 20}
 21
 22impl InvalidBufferView {
 23    pub fn new(
 24        abs_path: &Path,
 25        is_local: bool,
 26        e: &anyhow::Error,
 27        _: &mut Window,
 28        cx: &mut App,
 29    ) -> Self {
 30        Self {
 31            is_local,
 32            abs_path: Arc::from(abs_path),
 33            error: format!("{e}").into(),
 34            focus_handle: cx.focus_handle(),
 35        }
 36    }
 37}
 38
 39impl Item for InvalidBufferView {
 40    type Event = ();
 41
 42    fn tab_content_text(&self, mut detail: usize, _: &App) -> SharedString {
 43        // Ensure we always render at least the filename.
 44        detail += 1;
 45
 46        let path = self.abs_path.as_ref();
 47
 48        let mut prefix = path;
 49        while detail > 0 {
 50            if let Some(parent) = prefix.parent() {
 51                prefix = parent;
 52                detail -= 1;
 53            } else {
 54                break;
 55            }
 56        }
 57
 58        let path = if detail > 0 {
 59            path
 60        } else {
 61            path.strip_prefix(prefix).unwrap_or(path)
 62        };
 63
 64        SharedString::new(path.to_string_lossy())
 65    }
 66}
 67
 68impl EventEmitter<()> for InvalidBufferView {}
 69
 70impl Focusable for InvalidBufferView {
 71    fn focus_handle(&self, _: &App) -> FocusHandle {
 72        self.focus_handle.clone()
 73    }
 74}
 75
 76impl Render for InvalidBufferView {
 77    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl gpui::IntoElement {
 78        let abs_path = self.abs_path.clone();
 79        v_flex()
 80            .size_full()
 81            .track_focus(&self.focus_handle(cx))
 82            .flex_none()
 83            .justify_center()
 84            .overflow_hidden()
 85            .key_context("InvalidBuffer")
 86            .child(
 87                h_flex().size_full().justify_center().child(
 88                    v_flex()
 89                        .justify_center()
 90                        .gap_2()
 91                        .child(h_flex().justify_center().child("Unsupported file type"))
 92                        .when(self.is_local, |contents| {
 93                            contents.child(
 94                                h_flex().justify_center().child(
 95                                    Button::new("open-with-system", "Open in Default App")
 96                                        .on_click(move |_, _, cx| {
 97                                            cx.open_with_system(&abs_path);
 98                                        })
 99                                        .style(ButtonStyle::Outlined)
100                                        .key_binding(KeyBinding::for_action(
101                                            &OpenWithSystem,
102                                            window,
103                                            cx,
104                                        )),
105                                ),
106                            )
107                        }),
108                ),
109            )
110    }
111}