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}