refactor: use Cha for better cross-platform consistency (#3174)

This commit is contained in:
三咲雅 misaki masa 2025-09-17 23:18:54 +08:00 committed by GitHub
parent 6cfa92f112
commit ece59974fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 175 additions and 155 deletions

97
Cargo.lock generated
View file

@ -549,9 +549,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.5.57"
version = "4.5.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d9501bd3f5f09f7bbee01da9a511073ed30a80cd7a509f1214bb74eadea71ad"
checksum = "75bf0b32ad2e152de789bb635ea4d3078f6b838ad7974143e99b99f45a04af4a"
dependencies = [
"clap",
]
@ -1412,7 +1412,7 @@ dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi 0.14.5+wasi-0.2.4",
"wasi 0.14.7+wasi-0.2.4",
]
[[package]]
@ -1619,13 +1619,14 @@ checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
[[package]]
name = "indexmap"
version = "2.11.1"
version = "2.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921"
checksum = "92119844f513ffa41556430369ab02c295a3578af21cf945caa3e9e0c2481ac3"
dependencies = [
"equivalent",
"hashbrown 0.15.5",
"serde",
"serde_core",
]
[[package]]
@ -1778,9 +1779,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.78"
version = "0.3.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738"
checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e"
dependencies = [
"once_cell",
"wasm-bindgen",
@ -2561,9 +2562,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plist"
version = "1.7.4"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1"
checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07"
dependencies = [
"base64",
"indexmap",
@ -3202,9 +3203,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
version = "1.0.223"
version = "1.0.225"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac"
checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d"
dependencies = [
"serde_core",
"serde_derive",
@ -3222,18 +3223,18 @@ dependencies = [
[[package]]
name = "serde_core"
version = "1.0.223"
version = "1.0.225"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9"
checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.223"
version = "1.0.225"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56"
checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516"
dependencies = [
"proc-macro2",
"quote",
@ -3264,11 +3265,11 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
checksum = "2789234a13a53fc4be1b51ea1bab45a3c338bdb884862a257d10e5a74ae009e6"
dependencies = [
"serde",
"serde_core",
]
[[package]]
@ -3715,14 +3716,14 @@ dependencies = [
[[package]]
name = "toml"
version = "0.9.5"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8"
checksum = "ae2a4cf385da23d1d53bc15cdfa5c2109e93d8d362393c801e87da2f72f0e201"
dependencies = [
"indexmap",
"serde",
"serde_spanned 1.0.0",
"toml_datetime 0.7.0",
"serde_core",
"serde_spanned 1.0.1",
"toml_datetime 0.7.1",
"toml_parser",
"toml_writer",
"winnow",
@ -3739,11 +3740,11 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.7.0"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
checksum = "a197c0ec7d131bfc6f7e82c8442ba1595aeab35da7adbf05b6b73cd06a16b6be"
dependencies = [
"serde",
"serde_core",
]
[[package]]
@ -4045,27 +4046,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
version = "0.14.5+wasi-0.2.4"
version = "0.14.7+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4"
checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c"
dependencies = [
"wasip2",
]
[[package]]
name = "wasip2"
version = "1.0.0+wasi-0.2.4"
version = "1.0.1+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24"
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.101"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b"
checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819"
dependencies = [
"cfg-if",
"once_cell",
@ -4076,9 +4077,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.101"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb"
checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c"
dependencies = [
"bumpalo",
"log",
@ -4090,9 +4091,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.51"
version = "0.4.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe"
checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67"
dependencies = [
"cfg-if",
"js-sys",
@ -4103,9 +4104,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.101"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d"
checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -4113,9 +4114,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.101"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa"
checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32"
dependencies = [
"proc-macro2",
"quote",
@ -4126,18 +4127,18 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.101"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1"
checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf"
dependencies = [
"unicode-ident",
]
[[package]]
name = "web-sys"
version = "0.3.78"
version = "0.3.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12"
checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -4566,9 +4567,9 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
name = "wit-bindgen"
version = "0.45.1"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36"
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]]
name = "wyz"
@ -4693,7 +4694,7 @@ dependencies = [
"serde",
"serde_json",
"tokio",
"toml 0.9.5",
"toml 0.9.6",
"twox-hash",
"vergen-gitcl",
"yazi-boot",
@ -4725,7 +4726,7 @@ dependencies = [
"ratatui",
"regex",
"serde",
"toml 0.9.5",
"toml 0.9.6",
"tracing",
"yazi-codegen",
"yazi-fs",

View file

@ -32,7 +32,7 @@ foldhash = "0.2.0"
futures = "0.3.31"
globset = "0.4.16"
hashbrown = { version = "0.16.0", features = [ "serde" ] }
indexmap = { version = "2.11.1", features = [ "serde" ] }
indexmap = { version = "2.11.3", features = [ "serde" ] }
libc = "0.2.175"
lru = "0.16.1"
mlua = { version = "0.11.3", features = [ "anyhow", "async", "error-send", "lua54", "macros", "serde" ] }
@ -44,13 +44,13 @@ ratatui = { version = "0.29.0", features = [ "unstable-rendered-line
regex = "1.11.2"
russh = { version = "0.54.3", default-features = false, features = [ "ring", "rsa" ] }
scopeguard = "1.2.0"
serde = { version = "1.0.223", features = [ "derive" ] }
serde = { version = "1.0.225", features = [ "derive" ] }
serde_json = "1.0.145"
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
tokio = { version = "1.47.1", features = [ "full" ] }
tokio-stream = "0.1.17"
tokio-util = "0.7.16"
toml = { version = "0.9.5" }
toml = { version = "0.9.6" }
tracing = { version = "0.1.41", features = [ "max_level_debug", "release_max_level_debug" ] }
unicode-width = { version = "0.2.0", default-features = false }
twox-hash = { version = "2.1.2", default-features = false, features = [ "std", "random", "xxhash3_128" ] }

View file

@ -1,4 +1,4 @@
use std::{ops::Deref, time::{Duration, SystemTime, UNIX_EPOCH}};
use std::{ops::Deref, time::{Duration, SystemTime}};
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, UserDataMethods};
use yazi_fs::cha::{ChaKind, ChaMode};
@ -66,18 +66,10 @@ impl UserData for Cha {
fields.add_field_method_get("is_sticky", |_, me| Ok(me.is_sticky()));
fields.add_field_method_get("len", |_, me| Ok(me.len));
fields.add_field_method_get("atime", |_, me| {
Ok(me.atime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
fields.add_field_method_get("btime", |_, me| {
Ok(me.btime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
fields.add_field_method_get("ctime", |_, me| {
Ok(me.ctime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
fields.add_field_method_get("mtime", |_, me| {
Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
});
fields.add_field_method_get("atime", |_, me| Ok(me.atime_dur().ok().map(|d| d.as_secs_f64())));
fields.add_field_method_get("btime", |_, me| Ok(me.btime_dur().ok().map(|d| d.as_secs_f64())));
fields.add_field_method_get("ctime", |_, me| Ok(me.ctime_dur().ok().map(|d| d.as_secs_f64())));
fields.add_field_method_get("mtime", |_, me| Ok(me.mtime_dur().ok().map(|d| d.as_secs_f64())));
fields.add_field_method_get("dev", |_, me| Ok(me.dev));
fields.add_field_method_get("uid", |_, me| Ok(me.uid));
fields.add_field_method_get("gid", |_, me| Ok(me.gid));

View file

@ -27,7 +27,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
# External dependencies
clap = { workspace = true }
clap_complete = "4.5.57"
clap_complete = "4.5.58"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.8"
vergen-gitcl = { version = "1.0.8", features = [ "build", "rustc" ] }

View file

@ -41,7 +41,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.9.15" }
# External build dependencies
anyhow = { workspace = true }
clap = { workspace = true }
clap_complete = "4.5.57"
clap_complete = "4.5.58"
clap_complete_fig = "4.5.2"
clap_complete_nushell = "4.5.8"
serde_json = { workspace = true }

View file

@ -34,7 +34,7 @@ pub async fn copy_and_seal(from: &Path, to: &Path) -> io::Result<()> {
pub async fn remove_sealed(p: &Path) -> io::Result<()> {
#[cfg(windows)]
{
let mut perm = Local::metadata(p).await?.permissions();
let mut perm = tokio::fs::metadata(p).await?.permissions();
perm.set_readonly(false);
tokio::fs::set_permissions(p, perm).await?;
}

View file

@ -1,4 +1,4 @@
use std::{mem, ops::Deref, sync::atomic::{AtomicU64, Ordering}, time::UNIX_EPOCH};
use std::{mem, ops::Deref, sync::atomic::{AtomicU64, Ordering}};
use anyhow::Result;
use hashbrown::HashMap;
@ -103,8 +103,8 @@ impl State {
}
async fn skip(&self) -> Result<bool> {
let meta = Local::symlink_metadata(BOOT.state_dir.join(".dds")).await?;
let modified = meta.modified()?.duration_since(UNIX_EPOCH)?.as_micros();
let cha = Local::symlink_metadata(BOOT.state_dir.join(".dds")).await?;
let modified = cha.mtime_dur()?.as_micros();
Ok(modified >= self.last.load(Ordering::Relaxed) as u128)
}
}

View file

@ -1,5 +1,6 @@
use std::{fs::{FileType, Metadata}, ops::Deref, time::SystemTime};
use std::{ffi::OsStr, fs::{FileType, Metadata}, ops::Deref, time::{Duration, SystemTime, UNIX_EPOCH}};
use anyhow::bail;
use yazi_macro::{unix_either, win_either};
use yazi_shared::url::Url;
@ -47,11 +48,8 @@ impl Default for Cha {
impl Cha {
#[inline]
pub fn new<'a, U>(url: U, meta: Metadata) -> Self
where
U: Into<Url<'a>>,
{
Self::from_bare(&meta).attach(ChaKind::hidden(url, &meta))
pub fn new(name: &OsStr, meta: Metadata) -> Self {
Self::from_bare(&meta).attach(ChaKind::hidden(name, &meta))
}
#[inline]
@ -60,22 +58,21 @@ impl Cha {
Ok(Self::from_follow(url, provider::symlink_metadata(url).await?).await)
}
pub async fn from_follow<'a, U>(url: U, mut meta: Metadata) -> Self
pub async fn from_follow<'a, U>(url: U, mut cha: Self) -> Self
where
U: Into<Url<'a>>,
{
let url = url.into();
let mut attached = ChaKind::hidden(url, &meta);
let url: Url = url.into();
let mut retain = cha.kind & (ChaKind::HIDDEN | ChaKind::SYSTEM | ChaKind::LINK);
if meta.is_symlink() {
attached |= ChaKind::LINK;
meta = provider::metadata(url).await.unwrap_or(meta);
if cha.is_link() {
cha = provider::metadata(url).await.unwrap_or(cha);
}
if meta.is_symlink() {
attached |= ChaKind::ORPHAN;
if cha.is_link() {
retain |= ChaKind::ORPHAN;
}
Self::from_bare(&meta).attach(attached)
cha.attach(retain)
}
pub fn from_dummy<'a, U>(_url: U, ft: Option<FileType>) -> Self
@ -99,7 +96,7 @@ impl Cha {
fn from_bare(m: &Metadata) -> Self {
#[cfg(unix)]
use std::{os::unix::fs::MetadataExt, time::{Duration, UNIX_EPOCH}};
use std::os::unix::fs::MetadataExt;
#[cfg(unix)]
let mode = {
@ -169,4 +166,36 @@ impl Cha {
#[inline]
pub const fn is_dummy(&self) -> bool { self.kind.contains(ChaKind::DUMMY) }
pub fn atime_dur(&self) -> anyhow::Result<Duration> {
if let Some(atime) = self.atime {
Ok(atime.duration_since(UNIX_EPOCH)?)
} else {
bail!("atime not supported on this platform");
}
}
pub fn mtime_dur(&self) -> anyhow::Result<Duration> {
if let Some(mtime) = self.mtime {
Ok(mtime.duration_since(UNIX_EPOCH)?)
} else {
bail!("mtime not supported on this platform");
}
}
pub fn btime_dur(&self) -> anyhow::Result<Duration> {
if let Some(btime) = self.btime {
Ok(btime.duration_since(UNIX_EPOCH)?)
} else {
bail!("btime not supported on this platform");
}
}
pub fn ctime_dur(&self) -> anyhow::Result<Duration> {
if let Some(ctime) = self.ctime {
Ok(ctime.duration_since(UNIX_EPOCH)?)
} else {
bail!("ctime not supported on this platform");
}
}
}

View file

@ -1,7 +1,6 @@
use std::fs::Metadata;
use std::{ffi::OsStr, fs::Metadata};
use bitflags::bitflags;
use yazi_shared::url::Url;
bitflags! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
@ -18,15 +17,15 @@ bitflags! {
impl ChaKind {
#[inline]
pub(super) fn hidden<'a, U>(_url: U, _meta: &Metadata) -> Self
where
U: Into<Url<'a>>,
{
pub(super) fn hidden(_name: &OsStr, _meta: &Metadata) -> Self {
let mut me = Self::empty();
#[cfg(unix)]
if _url.into().urn().is_hidden() {
me |= Self::HIDDEN;
{
use std::os::unix::ffi::OsStrExt;
if _name.as_bytes().starts_with(b".") {
me |= Self::HIDDEN;
}
}
#[cfg(windows)]
{

View file

@ -1,4 +1,4 @@
use std::{ffi::OsStr, fs::{FileType, Metadata}, hash::{BuildHasher, Hash, Hasher}, ops::Deref, path::{Path, PathBuf}};
use std::{ffi::OsStr, fs::FileType, hash::{BuildHasher, Hash, Hasher}, ops::Deref, path::{Path, PathBuf}};
use anyhow::Result;
use yazi_shared::url::{Uri, UrlBuf, UrlCow, Urn};
@ -22,15 +22,15 @@ impl File {
#[inline]
pub async fn new(url: impl Into<UrlCow<'_>>) -> Result<Self> {
let url = url.into();
let meta = provider::symlink_metadata(&url).await?;
Ok(Self::from_follow(url.into_owned(), meta).await)
let cha = provider::symlink_metadata(&url).await?;
Ok(Self::from_follow(url.into_owned(), cha).await)
}
#[inline]
pub async fn from_follow(url: UrlBuf, meta: Metadata) -> Self {
let link_to = if meta.is_symlink() { provider::read_link(&url).await.ok() } else { None };
pub async fn from_follow(url: UrlBuf, cha: Cha) -> Self {
let link_to = if cha.is_link() { provider::read_link(&url).await.ok() } else { None };
let cha = Cha::from_follow(&url, meta).await;
let cha = Cha::from_follow(&url, cha).await;
Self { url, cha, link_to }
}

View file

@ -46,7 +46,7 @@ impl Files {
result = item.metadata() => {
let url = item.url();
_ = tx.send(match result {
Ok(meta) => File::from_follow(url, meta).await,
Ok(cha) => File::from_follow(url, cha).await,
Err(_) => File::from_dummy(url, item.file_type().await.ok())
});
}
@ -70,7 +70,7 @@ impl Files {
for entry in entries {
let url = entry.url();
files.push(match entry.metadata().await {
Ok(meta) => File::from_follow(url, meta).await,
Ok(cha) => File::from_follow(url, cha).await,
Err(_) => File::from_dummy(url, entry.file_type().await.ok()),
});
}

View file

@ -68,7 +68,7 @@ pub fn copy_with_progress(
None => {}
}
let len = provider::symlink_metadata(&to).await.map(|m| m.len()).unwrap_or(0);
let len = provider::symlink_metadata(&to).await.map(|m| m.len).unwrap_or(0);
if len > last {
prog_tx.send(Ok(len - last)).await.ok();
last = len;

View file

@ -15,11 +15,11 @@ impl SizeCalculator {
U: Into<Url<'a>>,
{
let url: Url = url.into();
let meta = provider::symlink_metadata(url).await?;
Ok(if meta.is_dir() {
let cha = provider::symlink_metadata(url).await?;
Ok(if cha.is_dir() {
Self::Dir(VecDeque::from([Either::Left(url.to_owned())]))
} else {
Self::File(Some(meta.len()))
Self::File(Some(cha.len))
})
}
@ -72,8 +72,8 @@ impl SizeCalculator {
let Ok(ft) = ent.file_type().await else { continue };
if ft.is_dir() {
buf.push_back(Either::Left(ent.url()));
} else if let Ok(meta) = ent.metadata().await {
size += meta.len();
} else if let Ok(cha) = ent.metadata().await {
size += cha.len;
}
}
Some(size)

View file

@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsStr, io};
use yazi_shared::url::UrlBuf;
use crate::provider::FileHolder;
use crate::{cha::Cha, provider::FileHolder};
pub enum DirEntry {
Local(super::local::DirEntry),
@ -27,7 +27,7 @@ impl DirEntry {
}
}
pub async fn metadata(&self) -> io::Result<std::fs::Metadata> {
pub async fn metadata(&self) -> io::Result<Cha> {
match self {
Self::Local(local) => local.metadata().await,
}

View file

@ -1,6 +1,6 @@
use std::{borrow::Cow, ffi::OsStr, io, path::PathBuf};
use crate::provider::FileHolder;
use crate::{cha::Cha, provider::FileHolder};
pub struct DirEntry(pub(super) tokio::fs::DirEntry);
@ -9,7 +9,10 @@ impl FileHolder for DirEntry {
fn name(&self) -> Cow<'_, OsStr> { self.0.file_name().into() }
async fn metadata(&self) -> io::Result<std::fs::Metadata> { self.0.metadata().await }
async fn metadata(&self) -> io::Result<Cha> {
let name = self.name(); // TODO: use `file_name_os_str` when stabilized
Ok(Cha::new(&name, self.0.metadata().await?))
}
async fn file_type(&self) -> io::Result<std::fs::FileType> { self.0.file_type().await }
}

View file

@ -62,11 +62,12 @@ impl Provider for Local {
}
#[inline]
async fn metadata<P>(path: P) -> io::Result<std::fs::Metadata>
async fn metadata<P>(path: P) -> io::Result<Cha>
where
P: AsRef<Path>,
{
tokio::fs::metadata(path).await
let path = path.as_ref();
Ok(Cha::new(path.file_name().unwrap_or_default(), tokio::fs::metadata(path).await?))
}
#[inline]
@ -170,11 +171,12 @@ impl Provider for Local {
}
#[inline]
async fn symlink_metadata<P>(path: P) -> io::Result<std::fs::Metadata>
async fn symlink_metadata<P>(path: P) -> io::Result<Cha>
where
P: AsRef<Path>,
{
tokio::fs::symlink_metadata(path).await
let path = path.as_ref();
Ok(Cha::new(path.file_name().unwrap_or_default(), tokio::fs::symlink_metadata(path).await?))
}
async fn trash<P>(path: P) -> io::Result<()>

View file

@ -125,7 +125,7 @@ where
}
#[inline]
pub async fn metadata<'a, U>(url: U) -> io::Result<std::fs::Metadata>
pub async fn metadata<'a, U>(url: U) -> io::Result<Cha>
where
U: Into<Url<'a>>,
{
@ -256,7 +256,7 @@ where
}
#[inline]
pub async fn symlink_metadata<'a, U>(url: U) -> io::Result<std::fs::Metadata>
pub async fn symlink_metadata<'a, U>(url: U) -> io::Result<Cha>
where
U: Into<Url<'a>>,
{

View file

@ -1,6 +1,6 @@
use std::{borrow::Cow, ffi::OsStr, io, path::PathBuf};
use crate::provider::{DirReader, FileHolder};
use crate::{cha::Cha, provider::{DirReader, FileHolder}};
pub struct ReadDir(pub(super) yazi_sftp::fs::ReadDir);
@ -20,7 +20,7 @@ impl FileHolder for DirEntry<'_> {
fn name(&self) -> Cow<'_, OsStr> { self.0.name() }
async fn metadata(&self) -> io::Result<std::fs::Metadata> { todo!() }
async fn metadata(&self) -> io::Result<Cha> { todo!() }
async fn file_type(&self) -> io::Result<std::fs::FileType> { todo!() }
}

View file

@ -1,4 +1,4 @@
use std::{io, path::{Path, PathBuf}, time::UNIX_EPOCH};
use std::{io, path::{Path, PathBuf}};
use yazi_sftp::fs::{Attrs, Flags};
@ -36,14 +36,8 @@ impl Provider for Sftp {
uid: Some(cha.uid),
gid: Some(cha.gid),
perm: Some(cha.mode.bits() as _),
atime: cha
.atime
.and_then(|t| t.duration_since(UNIX_EPOCH).ok())
.map(|d| d.as_secs() as u32),
mtime: cha
.mtime
.and_then(|t| t.duration_since(UNIX_EPOCH).ok())
.map(|d| d.as_secs() as u32),
atime: cha.atime_dur().ok().map(|d| d.as_secs() as u32),
mtime: cha.mtime_dur().ok().map(|d| d.as_secs() as u32),
extended: Default::default(),
};
@ -70,7 +64,7 @@ impl Provider for Sftp {
Ok(Self::op().await?.hardlink(&original, &link).await?)
}
async fn metadata<P>(path: P) -> io::Result<std::fs::Metadata>
async fn metadata<P>(path: P) -> io::Result<Cha>
where
P: AsRef<Path>,
{
@ -122,7 +116,7 @@ impl Provider for Sftp {
Ok(Self::op().await?.symlink(&original, &link).await?)
}
async fn symlink_metadata<P>(path: P) -> io::Result<std::fs::Metadata>
async fn symlink_metadata<P>(path: P) -> io::Result<Cha>
where
P: AsRef<Path>,
{

View file

@ -67,7 +67,7 @@ pub trait Provider {
P: AsRef<Path>,
Q: AsRef<Path>;
fn metadata<P>(path: P) -> impl Future<Output = io::Result<std::fs::Metadata>>
fn metadata<P>(path: P) -> impl Future<Output = io::Result<Cha>>
where
P: AsRef<Path>;
@ -115,8 +115,8 @@ pub trait Provider {
async move {
let path = path.as_ref();
let ft = ok_or_not_found!(Self::symlink_metadata(path).await, return Ok(()));
if ft.is_symlink() {
let cha = ok_or_not_found!(Self::symlink_metadata(path).await, return Ok(()));
if cha.is_link() {
Self::remove_file(path).await
} else {
remove_dir_all_impl::<Self>(path).await
@ -155,7 +155,7 @@ pub trait Provider {
Self::symlink(original, link, async || Ok(false))
}
fn symlink_metadata<P>(path: P) -> impl Future<Output = io::Result<std::fs::Metadata>>
fn symlink_metadata<P>(path: P) -> impl Future<Output = io::Result<Cha>>
where
P: AsRef<Path>;
@ -187,7 +187,7 @@ pub trait FileHolder {
fn name(&self) -> Cow<'_, OsStr>;
fn metadata(&self) -> impl Future<Output = io::Result<std::fs::Metadata>>;
fn metadata(&self) -> impl Future<Output = io::Result<Cha>>;
fn file_type(&self) -> impl Future<Output = io::Result<std::fs::FileType>>;
}

View file

@ -50,14 +50,14 @@ fn cwd(lua: &Lua) -> mlua::Result<Function> {
fn cha(lua: &Lua) -> mlua::Result<Function> {
lua.create_async_function(|lua, (url, follow): (UrlRef, Option<bool>)| async move {
let meta = if follow.unwrap_or(false) {
let cha = if follow.unwrap_or(false) {
provider::metadata(&*url).await
} else {
provider::symlink_metadata(&*url).await
};
match meta {
Ok(m) => Cha(yazi_fs::cha::Cha::new(&*url, m)).into_lua_multi(&lua),
match cha {
Ok(c) => Cha(c).into_lua_multi(&lua),
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
}
})
@ -129,8 +129,8 @@ fn read_dir(lua: &Lua) -> mlua::Result<Function> {
let file = if !resolve {
yazi_fs::File::from_dummy(url, next.file_type().await.ok())
} else if let Ok(meta) = next.metadata().await {
yazi_fs::File::from_follow(url, meta).await
} else if let Ok(cha) = next.metadata().await {
yazi_fs::File::from_follow(url, cha).await
} else {
yazi_fs::File::from_dummy(url, next.file_type().await.ok())
};

View file

@ -71,7 +71,7 @@ impl File {
let mut it = continue_unless_ok!(provider::read_dir(&src).await);
while let Ok(Some(entry)) = it.next_entry().await {
let from = entry.url();
let cha = continue_unless_ok!(Self::cha_from(entry, &from, task.follow).await);
let cha = continue_unless_ok!(Self::entry_cha(entry, &from, task.follow).await);
if cha.is_dir() {
dirs.push_back(from);
@ -205,7 +205,7 @@ impl File {
let mut it = continue_unless_ok!(provider::read_dir(&src).await);
while let Ok(Some(entry)) = it.next_entry().await {
let from = entry.url();
let cha = continue_unless_ok!(Self::cha_from(entry, &from, task.follow).await);
let cha = continue_unless_ok!(Self::entry_cha(entry, &from, task.follow).await);
if cha.is_dir() {
dirs.push_back(from);
@ -237,11 +237,11 @@ impl File {
}
pub(crate) async fn delete(&self, mut task: FileInDelete) -> Result<(), FileOutDelete> {
let meta = provider::symlink_metadata(&task.target).await?;
if !meta.is_dir() {
let cha = provider::symlink_metadata(&task.target).await?;
if !cha.is_dir() {
let id = task.id;
task.length = meta.len();
self.ops.out(id, FileOutDelete::New(meta.len()));
task.length = cha.len;
self.ops.out(id, FileOutDelete::New(cha.len));
self.queue(task, NORMAL);
self.ops.out(id, FileOutDelete::Init);
return Ok(());
@ -252,16 +252,16 @@ impl File {
let Ok(mut it) = provider::read_dir(&target).await else { continue };
while let Ok(Some(entry)) = it.next_entry().await {
let Ok(meta) = entry.metadata().await else { continue };
let Ok(cha) = entry.metadata().await else { continue };
if meta.is_dir() {
if cha.is_dir() {
dirs.push_front(entry.url());
continue;
}
task.target = entry.url();
task.length = meta.len();
self.ops.out(task.id, FileOutDelete::New(meta.len()));
task.length = cha.len;
self.ops.out(task.id, FileOutDelete::New(cha.len));
self.queue(task.clone(), NORMAL);
}
}
@ -291,16 +291,16 @@ impl File {
#[inline]
async fn cha<'a>(url: impl Into<Url<'a>>, follow: bool) -> io::Result<Cha> {
let url = url.into();
let meta = provider::symlink_metadata(url).await?;
Ok(if follow { Cha::from_follow(url, meta).await } else { Cha::new(url, meta) })
let cha = provider::symlink_metadata(url).await?;
Ok(if follow { Cha::from_follow(url, cha).await } else { cha })
}
#[inline]
async fn cha_from(entry: DirEntry, url: &UrlBuf, follow: bool) -> io::Result<Cha> {
async fn entry_cha(entry: DirEntry, url: &UrlBuf, follow: bool) -> io::Result<Cha> {
Ok(if follow {
Cha::from_follow(url, entry.metadata().await?).await
} else {
Cha::new(url, entry.metadata().await?)
entry.metadata().await?
})
}
}