fix: u16 instead of u32 as the type of max_width and max_height options (#3313)

This commit is contained in:
三咲雅 misaki masa 2025-11-05 08:53:30 +08:00 committed by GitHub
parent 97c63e2708
commit 587950bb5b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 162 additions and 33 deletions

View file

@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
- Rename `mime` fetcher to `mime.local`, and introduce `mime.dir` fetcher to support folder MIME types ([#3222])
- Remove `$0` parameter in opener rules to make the `open` command work under empty directories ([#3226])
- Use `body` instead of the term `content` in confirmations ([#2921])
- Use `u16` instead of `u32` as the type of `max_width` and `max_height` options to avoid memory exhaustion ([#3313])
- Implement `__pairs` metamethod instead of `__index` for the callback argument of the `@yank` DDS event ([#2997])
### Deprecated
@ -1533,3 +1534,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
[#3271]: https://github.com/sxyazi/yazi/pull/3271
[#3286]: https://github.com/sxyazi/yazi/pull/3286
[#3290]: https://github.com/sxyazi/yazi/pull/3290
[#3313]: https://github.com/sxyazi/yazi/pull/3313

View file

@ -65,10 +65,10 @@ impl Image {
Ok(img)
}
pub(super) fn max_pixel(rect: Rect) -> (u32, u32) {
pub(super) fn max_pixel(rect: Rect) -> (u16, u16) {
Dimension::cell_size()
.map(|(cw, ch)| {
let (w, h) = ((rect.width as f64 * cw) as u32, (rect.height as f64 * ch) as u32);
let (w, h) = ((rect.width as f64 * cw) as u16, (rect.height as f64 * ch) as u16);
(w.min(YAZI.preview.max_width), h.min(YAZI.preview.max_height))
})
.unwrap_or((YAZI.preview.max_width, YAZI.preview.max_height))
@ -122,11 +122,11 @@ impl Image {
.map_err(|e| ImageError::IoError(e.into()))?
}
fn flip_size(orientation: Orientation, (w, h): (u32, u32)) -> (u32, u32) {
fn flip_size(orientation: Orientation, (w, h): (u16, u16)) -> (u32, u32) {
use image::metadata::Orientation::{Rotate90, Rotate90FlipH, Rotate270, Rotate270FlipH};
match orientation {
Rotate90 | Rotate270 | Rotate90FlipH | Rotate270FlipH => (h, w),
_ => (w, h),
Rotate90 | Rotate270 | Rotate90FlipH | Rotate270FlipH => (h as u32, w as u32),
_ => (w as u32, h as u32),
}
}
}

View file

@ -15,8 +15,8 @@ const TABS: &[&str] = &["", " ", " ", " ", " ", " ", " ", "
pub struct Preview {
pub wrap: PreviewWrap,
pub tab_size: u8,
pub max_width: u32,
pub max_height: u32,
pub max_width: u16,
pub max_height: u16,
pub cache_dir: PathBuf,

View file

@ -1,6 +1,6 @@
use std::{ffi::OsStr, hash::{Hash, Hasher}, ops::Deref, path::{Path, PathBuf}};
use yazi_shared::url::{UrlBuf, UrlLike};
use yazi_shared::{path::PathDyn, url::{UrlBuf, UrlLike}};
use crate::cha::{Cha, ChaType};
@ -37,7 +37,7 @@ impl File {
pub fn url_owned(&self) -> UrlBuf { self.url.to_owned() }
#[inline]
pub fn uri(&self) -> &Path { self.url.uri() }
pub fn uri(&self) -> PathDyn<'_> { self.url.uri() }
#[inline]
pub fn urn(&self) -> &Path { self.url.urn() }

View file

@ -1,6 +1,6 @@
use std::{borrow::Cow, ffi::{OsStr, OsString}, path::{Path, PathBuf}};
use yazi_shared::{loc::LocBuf, url::{AsUrl, Url, UrlBuf, UrlCow}};
use yazi_shared::{loc::LocBuf, path::PathLike, url::{AsUrl, Url, UrlBuf, UrlCow}};
use crate::{CWD, path::clean_url};

View file

@ -40,9 +40,7 @@ function M:preload(job)
"-l", job.skip + 1,
"-singlefile",
"-jpeg", "-jpegopt", "quality=" .. rt.preview.image_quality,
"-scale-to-x", rt.preview.max_width, "-scale-to-y", "-1",
tostring(job.file.url),
tostring(cache),
tostring(job.file.url), tostring(cache),
})
:stderr(Command.PIPED)
:output()
@ -54,12 +52,7 @@ function M:preload(job)
return true, Err("Failed to convert PDF to image, stderr: %s", output.stderr), pages
end
local ok, err = os.rename(string.format("%s.jpg", cache), tostring(cache))
if ok then
return true
else
return false, Err("Failed to rename `%s.jpg` to `%s`, error: %s", cache, cache, err)
end
return ya.image_precache(Url(cache .. ".jpg"), cache)
end
return M

View file

@ -204,11 +204,8 @@ where
}
#[inline]
fn mutate<F: FnOnce(&mut P)>(&mut self, f: F)
where
P: Default,
{
let mut inner = std::mem::take(&mut self.inner);
fn mutate<F: FnOnce(&mut P)>(&mut self, f: F) {
let mut inner = self.inner.take();
f(&mut inner);
self.inner = Self::from(inner).inner;
}

View file

@ -4,7 +4,7 @@ use crate::path::{AsInnerView, AsPathView, PathInner, PathLike};
pub trait PathBufLike
where
Self: Default + 'static,
Self: 'static,
{
type Inner: for<'a> AsInnerView<'a, Self::InnerRef<'a>>;
type InnerRef<'a>: PathInner<'a>;
@ -21,6 +21,8 @@ where
fn set_file_name<T>(&mut self, name: T)
where
T: for<'a> AsInnerView<'a, Self::InnerRef<'a>>;
fn take(&mut self) -> Self;
}
impl PathBufLike for std::path::PathBuf {
@ -42,4 +44,6 @@ impl PathBufLike for std::path::PathBuf {
{
self.set_file_name(name.as_inner_view());
}
fn take(&mut self) -> Self { std::mem::take(self) }
}

View file

@ -1,9 +1,132 @@
use super::{AsInnerView, AsPathView};
use crate::path::{PathBufLike, PathLike};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum PathDyn<'p> {
Os(&'p std::path::Path),
}
impl<'a> AsPathView<'a, PathDyn<'a>> for PathDyn<'a> {
fn as_path_view(self) -> PathDyn<'a> { self }
}
impl<'a> AsPathView<'a, PathDyn<'a>> for std::path::Components<'a> {
fn as_path_view(self) -> PathDyn<'a> { PathDyn::Os(self.as_path()) }
}
impl<'a> From<&'a std::path::Path> for PathDyn<'a> {
fn from(value: &'a std::path::Path) -> Self { PathDyn::Os(value) }
}
impl<'p> PathLike<'p> for PathDyn<'p> {
type Components<'a> = std::path::Components<'a>;
type Inner = &'p [u8];
type Owned = PathBufDyn;
type View<'a> = PathDyn<'a>;
fn components(self) -> Self::Components<'p> {
match self {
Self::Os(p) => p.components(),
}
}
// FIXME: remove
fn default() -> Self { Self::Os(std::path::Path::new("")) }
fn encoded_bytes(self) -> &'p [u8] {
match self {
Self::Os(p) => p.as_os_str().as_encoded_bytes(),
}
}
fn extension(self) -> Option<Self::Inner> {
Some(match self {
Self::Os(p) => p.extension()?.as_encoded_bytes(),
})
}
fn file_name(self) -> Option<Self::Inner> {
Some(match self {
Self::Os(p) => p.file_name()?.as_encoded_bytes(),
})
}
fn file_stem(self) -> Option<Self::Inner> {
Some(match self {
Self::Os(p) => p.file_stem()?.as_encoded_bytes(),
})
}
// FIXME: remove
unsafe fn from_encoded_bytes(bytes: &'p [u8]) -> Self {
Self::Os(std::path::Path::new(unsafe { std::ffi::OsStr::from_encoded_bytes_unchecked(bytes) }))
}
fn join<'a, T>(self, base: T) -> Self::Owned
where
T: AsPathView<'a, Self::View<'a>>,
{
match (self, base.as_path_view()) {
(Self::Os(p), PathDyn::Os(q)) => Self::Owned::Os(p.join(q)),
}
}
fn parent(self) -> Option<Self> {
Some(match self {
Self::Os(p) => Self::Os(p.parent()?),
})
}
fn strip_prefix<'a, T>(self, base: T) -> Option<Self>
where
T: AsPathView<'a, Self::View<'a>>,
{
Some(match (self, base.as_path_view()) {
(Self::Os(p), PathDyn::Os(q)) => Self::Os(p.strip_prefix(q).ok()?),
})
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum PathBufDyn {
Os(std::path::PathBuf),
}
impl PathBufLike for PathBufDyn {
type Borrowed<'a> = PathDyn<'a>;
type Inner = Vec<u8>;
type InnerRef<'a> = &'a [u8];
fn encoded_bytes(&self) -> &[u8] {
match self {
Self::Os(p) => p.as_os_str().as_encoded_bytes(),
}
}
// FIXME: remove
unsafe fn from_encoded_bytes(bytes: Vec<u8>) -> Self {
Self::Os(std::path::PathBuf::from(unsafe {
std::ffi::OsString::from_encoded_bytes_unchecked(bytes)
}))
}
fn into_encoded_bytes(self) -> Vec<u8> {
match self {
Self::Os(p) => p.into_os_string().into_encoded_bytes(),
}
}
fn set_file_name<T>(&mut self, name: T)
where
T: for<'a> AsInnerView<'a, Self::InnerRef<'a>>,
{
// TODO: introduce a new `PathInnerDyn`
todo!()
}
fn take(&mut self) -> Self {
match self {
Self::Os(p) => Self::Os(std::mem::take(p)),
}
}
}

View file

@ -23,6 +23,8 @@ where
unsafe fn from_encoded_bytes(bytes: &'p [u8]) -> Self;
fn is_empty(self) -> bool { self.encoded_bytes().is_empty() }
#[cfg(unix)]
fn is_hidden(self) -> bool {
self.file_name().map_or(false, |n| n.encoded_bytes().get(0) == Some(&b'.'))

View file

@ -82,6 +82,14 @@ impl<'a> AsInnerView<'a, &'a std::ffi::OsStr> for std::ffi::OsString {
fn as_inner_view(&'a self) -> &'a std::ffi::OsStr { self }
}
impl<'a> AsInnerView<'a, &'a [u8]> for [u8] {
fn as_inner_view(&'a self) -> &'a [u8] { self }
}
impl<'a> AsInnerView<'a, &'a [u8]> for Vec<u8> {
fn as_inner_view(&'a self) -> &'a [u8] { self }
}
impl<'a, T, U> AsInnerView<'a, U> for &T
where
T: ?Sized + AsInnerView<'a, U>,

View file

@ -1,6 +1,6 @@
use std::{borrow::Cow, ffi::OsStr, path::{Path, PathBuf}};
use crate::{loc::Loc, scheme::{AsScheme, SchemeRef}, url::{Components, Display, Url, UrlBuf, UrlCow}};
use crate::{loc::Loc, path::PathDyn, scheme::{AsScheme, SchemeRef}, url::{Components, Display, Url, UrlBuf, UrlCow}};
// --- AsUrl
pub trait AsUrl {
@ -117,7 +117,7 @@ where
fn strip_prefix(&self, base: impl AsUrl) -> Option<&Path> { self.as_url().strip_prefix(base) }
fn uri(&self) -> &Path { self.as_url().uri() }
fn uri(&self) -> PathDyn<'_> { self.as_url().uri() }
fn urn(&self) -> &Path { self.as_url().urn() }
}

View file

@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::{Path, PathBuf
use hashbrown::Equivalent;
use crate::{loc::{Loc, LocBuf}, scheme::SchemeRef, url::{AsUrl, Components, Encode, UrlBuf}};
use crate::{loc::{Loc, LocBuf}, path::{PathDyn, PathLike}, scheme::SchemeRef, url::{AsUrl, Components, Encode, UrlBuf}};
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct Url<'a> {
@ -97,10 +97,10 @@ impl<'a> Url<'a> {
(S::Search(_), S::Regular) => Some(prefix),
// Only the entry of archives is a local file
(S::Regular, S::Archive(_)) => Some(prefix).filter(|_| base.uri().as_os_str().is_empty()),
(S::Search(_), S::Archive(_)) => Some(prefix).filter(|_| base.uri().as_os_str().is_empty()),
(S::Archive(_), S::Regular) => Some(prefix).filter(|_| self.uri().as_os_str().is_empty()),
(S::Archive(_), S::Search(_)) => Some(prefix).filter(|_| self.uri().as_os_str().is_empty()),
(S::Regular, S::Archive(_)) => Some(prefix).filter(|_| base.uri().is_empty()),
(S::Search(_), S::Archive(_)) => Some(prefix).filter(|_| base.uri().is_empty()),
(S::Archive(_), S::Regular) => Some(prefix).filter(|_| self.uri().is_empty()),
(S::Archive(_), S::Search(_)) => Some(prefix).filter(|_| self.uri().is_empty()),
// Independent virtual file space
(S::Regular, S::Sftp(_)) => None,
@ -113,7 +113,7 @@ impl<'a> Url<'a> {
}
#[inline]
pub fn uri(self) -> &'a Path { self.loc.uri() }
pub fn uri(self) -> PathDyn<'a> { self.loc.uri().into() }
#[inline]
pub fn urn(self) -> &'a Path { self.loc.urn() }