Closes https://github.com/zed-industries/zed/discussions/40763 <img width="867" height="1088" alt="Screenshot 2025-10-21 at 23 14 47" src="https://github.com/user-attachments/assets/d691fb2a-afc6-4445-a335-054ef164e0d3" /> Also improves error handling on image open failure: <img width="864" height="1083" alt="Screenshot 2025-10-21 at 23 14 30" src="https://github.com/user-attachments/assets/d5388b61-995f-441b-b375-ad5136d1533b" /> Release Notes: - Added basic ico support, improved unsupported image handling
119 lines
3.7 KiB
Rust
119 lines
3.7 KiB
Rust
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,
|
|
)),
|
|
),
|
|
)
|
|
}),
|
|
),
|
|
)
|
|
}
|
|
}
|