From 590d3367160734cef447ea445e5fb9ef74ca0c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Tue, 24 Jun 2025 16:47:39 +0800 Subject: [PATCH] feat: fill in error messages if preview fails (#2917) --- yazi-adapter/src/image.rs | 4 ++-- yazi-plugin/preset/plugins/font.lua | 12 +++++++----- yazi-plugin/preset/plugins/magick.lua | 12 +++++++----- yazi-plugin/preset/plugins/pdf.lua | 4 ++-- yazi-plugin/preset/plugins/svg.lua | 12 +++++++----- yazi-plugin/preset/plugins/video.lua | 12 +++++++----- yazi-plugin/src/elements/area.rs | 4 ++++ yazi-plugin/src/elements/renderable.rs | 23 +++++++++++++++++++++-- yazi-plugin/src/elements/wrap.rs | 4 ++++ yazi-plugin/src/utils/image.rs | 7 +++++-- yazi-plugin/src/utils/preview.rs | 12 +++++++++++- 11 files changed, 77 insertions(+), 29 deletions(-) diff --git a/yazi-adapter/src/image.rs b/yazi-adapter/src/image.rs index d9b56593..9df206f0 100644 --- a/yazi-adapter/src/image.rs +++ b/yazi-adapter/src/image.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use anyhow::Result; use image::{DynamicImage, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageReader, ImageResult, Limits, codecs::{jpeg::JpegEncoder, png::PngEncoder}, imageops::FilterType, metadata::Orientation}; @@ -10,7 +10,7 @@ use crate::Dimension; pub struct Image; impl Image { - pub async fn precache(path: &Path, cache: PathBuf) -> Result<()> { + pub async fn precache(path: &Path, cache: &Path) -> Result<()> { let (mut img, orientation, icc) = Self::decode_from(path).await?; let (w, h) = Self::flip_size(orientation, (YAZI.preview.max_width, YAZI.preview.max_height)); diff --git a/yazi-plugin/preset/plugins/font.lua b/yazi-plugin/preset/plugins/font.lua index 61d4032c..070e2534 100644 --- a/yazi-plugin/preset/plugins/font.lua +++ b/yazi-plugin/preset/plugins/font.lua @@ -10,13 +10,13 @@ function M:peek(job) local ok, err = self:preload(job) if not ok or err then - return + return ya.preview_widget(job, err) end ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) local _, err = ya.image_show(cache, job.area) - ya.preview_widget(job, err and ui.Text(err):area(job.area):wrap(ui.Wrap.YES)) + ya.preview_widget(job, err) end function M:seek() end @@ -45,10 +45,12 @@ function M:preload(job) "JPG:" .. tostring(cache), }):status() - if status then - return status.success - else + if not status then return true, Err("Failed to start `magick`, error: %s", err) + elseif not status.success then + return false, Err("`magick` exited with error code: %s", status.code) + else + return true end end diff --git a/yazi-plugin/preset/plugins/magick.lua b/yazi-plugin/preset/plugins/magick.lua index 649e0fbe..2f1b4af7 100644 --- a/yazi-plugin/preset/plugins/magick.lua +++ b/yazi-plugin/preset/plugins/magick.lua @@ -8,13 +8,13 @@ function M:peek(job) local ok, err = self:preload(job) if not ok or err then - return + return ya.preview_widget(job, err) end ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) local _, err = ya.image_show(cache, job.area) - ya.preview_widget(job, err and ui.Text(err):area(job.area):wrap(ui.Wrap.YES)) + ya.preview_widget(job, err) end function M:seek() end @@ -38,10 +38,12 @@ function M:preload(job) string.format("JPG:%s", cache), }:status() - if status then - return status.success - else + if not status then return true, Err("Failed to start `magick`, error: %s", err) + elseif not status.success then + return false, Err("`magick` exited with error code: %s", status.code) + else + return true end end diff --git a/yazi-plugin/preset/plugins/pdf.lua b/yazi-plugin/preset/plugins/pdf.lua index 662ba188..658d78e5 100644 --- a/yazi-plugin/preset/plugins/pdf.lua +++ b/yazi-plugin/preset/plugins/pdf.lua @@ -8,13 +8,13 @@ function M:peek(job) local ok, err = self:preload(job) if not ok or err then - return + return ya.preview_widget(job, err) end ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) local _, err = ya.image_show(cache, job.area) - ya.preview_widget(job, err and ui.Text(err):area(job.area):wrap(ui.Wrap.YES)) + ya.preview_widget(job, err) end function M:seek(job) diff --git a/yazi-plugin/preset/plugins/svg.lua b/yazi-plugin/preset/plugins/svg.lua index b61edc1a..6b1fa189 100644 --- a/yazi-plugin/preset/plugins/svg.lua +++ b/yazi-plugin/preset/plugins/svg.lua @@ -8,13 +8,13 @@ function M:peek(job) local ok, err = self:preload(job) if not ok or err then - return + return ya.preview_widget(job, err) end ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) local _, err = ya.image_show(cache, job.area) - ya.preview_widget(job, err and ui.Text(err):area(job.area):wrap(ui.Wrap.YES)) + ya.preview_widget(job, err) end function M:seek() end @@ -60,10 +60,12 @@ function M:preload(job) end end - if status then - return status.success - else + if not status then return true, Err("Error while running `resvg`: %s", err) + elseif not status.success then + return false, Err("`resvg` exited with error code: %s", status.code) + else + return true end end diff --git a/yazi-plugin/preset/plugins/video.lua b/yazi-plugin/preset/plugins/video.lua index dc0251c2..3edefcc6 100644 --- a/yazi-plugin/preset/plugins/video.lua +++ b/yazi-plugin/preset/plugins/video.lua @@ -8,13 +8,13 @@ function M:peek(job) local ok, err = self:preload(job) if not ok or err then - return + return ya.preview_widget(job, err) end ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock())) local _, err = ya.image_show(cache, job.area) - ya.preview_widget(job, err and ui.Text(err):area(job.area):wrap(ui.Wrap.YES)) + ya.preview_widget(job, err) end function M:seek(job) @@ -76,10 +76,12 @@ function M:preload(job) "-y", tostring(cache), }):status() - if status then - return status.success - else + if not status then return true, Err("Failed to start `ffmpeg`, error: %s", err) + elseif not status.success then + return false, Err("`ffmpeg` exited with error code: %s", status.code) + else + return true end end diff --git a/yazi-plugin/src/elements/area.rs b/yazi-plugin/src/elements/area.rs index 91db89c4..23971939 100644 --- a/yazi-plugin/src/elements/area.rs +++ b/yazi-plugin/src/elements/area.rs @@ -50,6 +50,10 @@ impl Area { } } +impl From for Area { + fn from(rect: Rect) -> Self { Self::Rect(rect) } +} + impl TryFrom for Area { type Error = mlua::Error; diff --git a/yazi-plugin/src/elements/renderable.rs b/yazi-plugin/src/elements/renderable.rs index c42d5d7c..7f643277 100644 --- a/yazi-plugin/src/elements/renderable.rs +++ b/yazi-plugin/src/elements/renderable.rs @@ -1,8 +1,10 @@ use std::any::TypeId; use mlua::{AnyUserData, ExternalError}; +use yazi_binding::Error; use super::{Bar, Border, Clear, Gauge, Line, List, Table, Text}; +use crate::elements::Rect; #[derive(Clone, Debug)] pub enum Renderable { @@ -35,10 +37,10 @@ impl Renderable { } } -impl TryFrom for Renderable { +impl TryFrom<&AnyUserData> for Renderable { type Error = mlua::Error; - fn try_from(ud: AnyUserData) -> Result { + fn try_from(ud: &AnyUserData) -> Result { Ok(match ud.type_id() { Some(t) if t == TypeId::of::() => Self::Line(ud.take()?), Some(t) if t == TypeId::of::() => Self::Text(ud.take()?), @@ -52,3 +54,20 @@ impl TryFrom for Renderable { }) } } + +impl TryFrom for Renderable { + type Error = mlua::Error; + + fn try_from(ud: AnyUserData) -> Result { Self::try_from(&ud) } +} + +impl From<(Rect, Error)> for Renderable { + fn from((area, error): (Rect, Error)) -> Self { + Self::Text(Text { + area: area.into(), + inner: error.into_string().into(), + wrap: ratatui::widgets::Wrap { trim: false }.into(), + ..Default::default() + }) + } +} diff --git a/yazi-plugin/src/elements/wrap.rs b/yazi-plugin/src/elements/wrap.rs index 127e8bbf..c76c82f8 100644 --- a/yazi-plugin/src/elements/wrap.rs +++ b/yazi-plugin/src/elements/wrap.rs @@ -18,6 +18,10 @@ impl Wrap { } } +impl From for Wrap { + fn from(value: ratatui::widgets::Wrap) -> Self { Self(Some(value)) } +} + impl From for Wrap { fn from(value: PreviewWrap) -> Self { Self(match value { diff --git a/yazi-plugin/src/utils/image.rs b/yazi-plugin/src/utils/image.rs index b03e2180..b1c700ab 100644 --- a/yazi-plugin/src/utils/image.rs +++ b/yazi-plugin/src/utils/image.rs @@ -25,8 +25,11 @@ impl Utils { } pub(super) fn image_precache(lua: &Lua) -> mlua::Result { - lua.create_async_function(|_, (src, dist): (UrlRef, UrlRef)| async move { - Ok(Image::precache(&src, dist.to_path_buf()).await.is_ok()) + lua.create_async_function(|lua, (src, dist): (UrlRef, UrlRef)| async move { + match Image::precache(&src, &dist).await { + Ok(()) => true.into_lua_multi(&lua), + Err(e) => (false, Error::Custom(e.to_string().into())).into_lua_multi(&lua), + } }) } } diff --git a/yazi-plugin/src/utils/preview.rs b/yazi-plugin/src/utils/preview.rs index 4ae11dde..e3fd6784 100644 --- a/yazi-plugin/src/utils/preview.rs +++ b/yazi-plugin/src/utils/preview.rs @@ -1,4 +1,5 @@ use mlua::{AnyUserData, ExternalError, Function, IntoLuaMulti, Lua, Table, Value}; +use yazi_binding::Error; use yazi_config::YAZI; use yazi_macro::emit; use yazi_shared::{errors::PeekError, event::Cmd}; @@ -69,7 +70,16 @@ impl Utils { .sequence_values::() .map(|ud| ud.and_then(Renderable::try_from)) .collect::>()?, - Value::UserData(ud) => vec![Renderable::try_from(ud)?], + Value::UserData(ud) => match Renderable::try_from(&ud) { + Ok(r) => vec![r], + Err(e) => { + if let Ok(err) = ud.take::() { + vec![(lock.area, err).into()] + } else { + Err(e)? + } + } + }, _ => Err("preview widget must be a renderable element or a table of them".into_lua_err())?, };