mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: fill in error messages if preview fails (#2917)
This commit is contained in:
parent
e218f1d8bb
commit
590d336716
11 changed files with 77 additions and 29 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use image::{DynamicImage, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageReader, ImageResult, Limits, codecs::{jpeg::JpegEncoder, png::PngEncoder}, imageops::FilterType, metadata::Orientation};
|
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;
|
pub struct Image;
|
||||||
|
|
||||||
impl 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 (mut img, orientation, icc) = Self::decode_from(path).await?;
|
||||||
let (w, h) = Self::flip_size(orientation, (YAZI.preview.max_width, YAZI.preview.max_height));
|
let (w, h) = Self::flip_size(orientation, (YAZI.preview.max_width, YAZI.preview.max_height));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ function M:peek(job)
|
||||||
|
|
||||||
local ok, err = self:preload(job)
|
local ok, err = self:preload(job)
|
||||||
if not ok or err then
|
if not ok or err then
|
||||||
return
|
return ya.preview_widget(job, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
||||||
|
|
||||||
local _, err = ya.image_show(cache, job.area)
|
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
|
end
|
||||||
|
|
||||||
function M:seek() end
|
function M:seek() end
|
||||||
|
|
@ -45,10 +45,12 @@ function M:preload(job)
|
||||||
"JPG:" .. tostring(cache),
|
"JPG:" .. tostring(cache),
|
||||||
}):status()
|
}):status()
|
||||||
|
|
||||||
if status then
|
if not status then
|
||||||
return status.success
|
|
||||||
else
|
|
||||||
return true, Err("Failed to start `magick`, error: %s", err)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ function M:peek(job)
|
||||||
|
|
||||||
local ok, err = self:preload(job)
|
local ok, err = self:preload(job)
|
||||||
if not ok or err then
|
if not ok or err then
|
||||||
return
|
return ya.preview_widget(job, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
||||||
|
|
||||||
local _, err = ya.image_show(cache, job.area)
|
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
|
end
|
||||||
|
|
||||||
function M:seek() end
|
function M:seek() end
|
||||||
|
|
@ -38,10 +38,12 @@ function M:preload(job)
|
||||||
string.format("JPG:%s", cache),
|
string.format("JPG:%s", cache),
|
||||||
}:status()
|
}:status()
|
||||||
|
|
||||||
if status then
|
if not status then
|
||||||
return status.success
|
|
||||||
else
|
|
||||||
return true, Err("Failed to start `magick`, error: %s", err)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ function M:peek(job)
|
||||||
|
|
||||||
local ok, err = self:preload(job)
|
local ok, err = self:preload(job)
|
||||||
if not ok or err then
|
if not ok or err then
|
||||||
return
|
return ya.preview_widget(job, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
||||||
|
|
||||||
local _, err = ya.image_show(cache, job.area)
|
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
|
end
|
||||||
|
|
||||||
function M:seek(job)
|
function M:seek(job)
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ function M:peek(job)
|
||||||
|
|
||||||
local ok, err = self:preload(job)
|
local ok, err = self:preload(job)
|
||||||
if not ok or err then
|
if not ok or err then
|
||||||
return
|
return ya.preview_widget(job, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
||||||
|
|
||||||
local _, err = ya.image_show(cache, job.area)
|
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
|
end
|
||||||
|
|
||||||
function M:seek() end
|
function M:seek() end
|
||||||
|
|
@ -60,10 +60,12 @@ function M:preload(job)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if status then
|
if not status then
|
||||||
return status.success
|
|
||||||
else
|
|
||||||
return true, Err("Error while running `resvg`: %s", err)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ function M:peek(job)
|
||||||
|
|
||||||
local ok, err = self:preload(job)
|
local ok, err = self:preload(job)
|
||||||
if not ok or err then
|
if not ok or err then
|
||||||
return
|
return ya.preview_widget(job, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
ya.sleep(math.max(0, rt.preview.image_delay / 1000 + start - os.clock()))
|
||||||
|
|
||||||
local _, err = ya.image_show(cache, job.area)
|
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
|
end
|
||||||
|
|
||||||
function M:seek(job)
|
function M:seek(job)
|
||||||
|
|
@ -76,10 +76,12 @@ function M:preload(job)
|
||||||
"-y", tostring(cache),
|
"-y", tostring(cache),
|
||||||
}):status()
|
}):status()
|
||||||
|
|
||||||
if status then
|
if not status then
|
||||||
return status.success
|
|
||||||
else
|
|
||||||
return true, Err("Failed to start `ffmpeg`, error: %s", err)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ impl Area {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Rect> for Area {
|
||||||
|
fn from(rect: Rect) -> Self { Self::Rect(rect) }
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<AnyUserData> for Area {
|
impl TryFrom<AnyUserData> for Area {
|
||||||
type Error = mlua::Error;
|
type Error = mlua::Error;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
|
||||||
use mlua::{AnyUserData, ExternalError};
|
use mlua::{AnyUserData, ExternalError};
|
||||||
|
use yazi_binding::Error;
|
||||||
|
|
||||||
use super::{Bar, Border, Clear, Gauge, Line, List, Table, Text};
|
use super::{Bar, Border, Clear, Gauge, Line, List, Table, Text};
|
||||||
|
use crate::elements::Rect;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Renderable {
|
pub enum Renderable {
|
||||||
|
|
@ -35,10 +37,10 @@ impl Renderable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<AnyUserData> for Renderable {
|
impl TryFrom<&AnyUserData> for Renderable {
|
||||||
type Error = mlua::Error;
|
type Error = mlua::Error;
|
||||||
|
|
||||||
fn try_from(ud: AnyUserData) -> Result<Self, Self::Error> {
|
fn try_from(ud: &AnyUserData) -> Result<Self, Self::Error> {
|
||||||
Ok(match ud.type_id() {
|
Ok(match ud.type_id() {
|
||||||
Some(t) if t == TypeId::of::<Line>() => Self::Line(ud.take()?),
|
Some(t) if t == TypeId::of::<Line>() => Self::Line(ud.take()?),
|
||||||
Some(t) if t == TypeId::of::<Text>() => Self::Text(ud.take()?),
|
Some(t) if t == TypeId::of::<Text>() => Self::Text(ud.take()?),
|
||||||
|
|
@ -52,3 +54,20 @@ impl TryFrom<AnyUserData> for Renderable {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<AnyUserData> for Renderable {
|
||||||
|
type Error = mlua::Error;
|
||||||
|
|
||||||
|
fn try_from(ud: AnyUserData) -> Result<Self, Self::Error> { 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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@ impl Wrap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ratatui::widgets::Wrap> for Wrap {
|
||||||
|
fn from(value: ratatui::widgets::Wrap) -> Self { Self(Some(value)) }
|
||||||
|
}
|
||||||
|
|
||||||
impl From<PreviewWrap> for Wrap {
|
impl From<PreviewWrap> for Wrap {
|
||||||
fn from(value: PreviewWrap) -> Self {
|
fn from(value: PreviewWrap) -> Self {
|
||||||
Self(match value {
|
Self(match value {
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,11 @@ impl Utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn image_precache(lua: &Lua) -> mlua::Result<Function> {
|
pub(super) fn image_precache(lua: &Lua) -> mlua::Result<Function> {
|
||||||
lua.create_async_function(|_, (src, dist): (UrlRef, UrlRef)| async move {
|
lua.create_async_function(|lua, (src, dist): (UrlRef, UrlRef)| async move {
|
||||||
Ok(Image::precache(&src, dist.to_path_buf()).await.is_ok())
|
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),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use mlua::{AnyUserData, ExternalError, Function, IntoLuaMulti, Lua, Table, Value};
|
use mlua::{AnyUserData, ExternalError, Function, IntoLuaMulti, Lua, Table, Value};
|
||||||
|
use yazi_binding::Error;
|
||||||
use yazi_config::YAZI;
|
use yazi_config::YAZI;
|
||||||
use yazi_macro::emit;
|
use yazi_macro::emit;
|
||||||
use yazi_shared::{errors::PeekError, event::Cmd};
|
use yazi_shared::{errors::PeekError, event::Cmd};
|
||||||
|
|
@ -69,7 +70,16 @@ impl Utils {
|
||||||
.sequence_values::<AnyUserData>()
|
.sequence_values::<AnyUserData>()
|
||||||
.map(|ud| ud.and_then(Renderable::try_from))
|
.map(|ud| ud.and_then(Renderable::try_from))
|
||||||
.collect::<mlua::Result<_>>()?,
|
.collect::<mlua::Result<_>>()?,
|
||||||
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::<Error>() {
|
||||||
|
vec![(lock.area, err).into()]
|
||||||
|
} else {
|
||||||
|
Err(e)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => Err("preview widget must be a renderable element or a table of them".into_lua_err())?,
|
_ => Err("preview widget must be a renderable element or a table of them".into_lua_err())?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue