invalid_item_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, Label, LabelCommon, LabelSize, ParentElement, Render, SharedString, Styled as _,
  7    TintColor, Window, div, h_flex, v_flex,
  8};
  9use zed_actions::workspace::OpenWithSystem;
 10
 11use crate::Item;
 12
 13/// A view to display when a certain buffer fails to open.
 14#[derive(Debug)]
 15pub struct InvalidItemView {
 16    /// Which path was attempted to open.
 17    pub abs_path: Arc<Path>,
 18    /// An error message, happened when opening the buffer.
 19    pub error: SharedString,
 20    is_local: bool,
 21    focus_handle: FocusHandle,
 22}
 23
 24impl InvalidItemView {
 25    pub fn new(
 26        abs_path: &Path,
 27        is_local: bool,
 28        e: &anyhow::Error,
 29        _: &mut Window,
 30        cx: &mut App,
 31    ) -> Self {
 32        Self {
 33            is_local,
 34            abs_path: Arc::from(abs_path),
 35            error: format!("{}", e.root_cause()).into(),
 36            focus_handle: cx.focus_handle(),
 37        }
 38    }
 39}
 40
 41impl Item for InvalidItemView {
 42    type Event = ();
 43
 44    fn tab_content_text(&self, mut detail: usize, _: &App) -> SharedString {
 45        // Ensure we always render at least the filename.
 46        detail += 1;
 47
 48        let path = self.abs_path.as_ref();
 49
 50        let mut prefix = path;
 51        while detail > 0 {
 52            if let Some(parent) = prefix.parent() {
 53                prefix = parent;
 54                detail -= 1;
 55            } else {
 56                break;
 57            }
 58        }
 59
 60        let path = if detail > 0 {
 61            path
 62        } else {
 63            path.strip_prefix(prefix).unwrap_or(path)
 64        };
 65
 66        SharedString::new(path.to_string_lossy())
 67    }
 68}
 69
 70impl EventEmitter<()> for InvalidItemView {}
 71
 72impl Focusable for InvalidItemView {
 73    fn focus_handle(&self, _: &App) -> FocusHandle {
 74        self.focus_handle.clone()
 75    }
 76}
 77
 78impl Render for InvalidItemView {
 79    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl gpui::IntoElement {
 80        let abs_path = self.abs_path.clone();
 81        let path0 = self.abs_path.clone();
 82        let path1 = self.abs_path.clone();
 83
 84        v_flex()
 85            .size_full()
 86            .track_focus(&self.focus_handle(cx))
 87            .flex_none()
 88            .justify_center()
 89            .overflow_hidden()
 90            .key_context("InvalidBuffer")
 91            .child(
 92                h_flex().size_full().justify_center().items_center().child(
 93                    v_flex()
 94                        .gap_2()
 95                        .max_w_96()
 96                        .child(h_flex().justify_center().child("Could not open file"))
 97                        .child(
 98                            h_flex().justify_center().child(
 99                                div()
100                                    .whitespace_normal()
101                                    .text_center()
102                                    .child(Label::new(self.error.clone()).size(LabelSize::Small)),
103                            ),
104                        )
105                        .when(self.is_local, |contents| {
106                            contents
107                                .child(
108                                    h_flex().justify_center().child(
109                                        Button::new("open-with-system", "Open in Default App")
110                                            .on_click(move |_, _, cx| {
111                                                cx.open_with_system(&abs_path);
112                                            })
113                                            .style(ButtonStyle::Outlined)
114                                            .key_binding(KeyBinding::for_action(
115                                                &OpenWithSystem,
116                                                window,
117                                                cx,
118                                            )),
119                                    ),
120                                )
121                                .child(
122                                    h_flex()
123                                        .justify_center()
124                                        .child(
125                                            Button::new(
126                                                "open-with-encoding",
127                                                "Open With a Different Encoding",
128                                            )
129                                            .style(ButtonStyle::Outlined)
130                                            .on_click(
131                                                move |_, window, cx| {
132                                                    window.dispatch_action(
133                                                        Box::new(
134                                                            zed_actions::encodings_ui::Toggle(
135                                                                path0.clone(),
136                                                            ),
137                                                        ),
138                                                        cx,
139                                                    )
140                                                },
141                                            ),
142                                        )
143                                        .child(
144                                            Button::new(
145                                                "accept-risk-and-open",
146                                                "Accept the Risk and Open",
147                                            )
148                                            .style(ButtonStyle::Tinted(TintColor::Warning))
149                                            .on_click(
150                                                move |_, window, cx| {
151                                                    window.dispatch_action(
152                                                        Box::new(
153                                                            zed_actions::encodings_ui::ForceOpen(
154                                                                path1.clone(),
155                                                            ),
156                                                        ),
157                                                        cx,
158                                                    );
159                                                },
160                                            ),
161                                        ),
162                                )
163                        }),
164                ),
165            )
166    }
167}