mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
refactor: use Cha for better cross-platform consistency
This commit is contained in:
parent
6cfa92f112
commit
7a23f2a4c1
16 changed files with 78 additions and 77 deletions
|
|
@ -1,6 +1,6 @@
|
|||
use std::{mem, ops::Deref, sync::atomic::{AtomicU64, Ordering}, time::UNIX_EPOCH};
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{Result, anyhow};
|
||||
use hashbrown::HashMap;
|
||||
use parking_lot::RwLock;
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter};
|
||||
|
|
@ -103,8 +103,9 @@ 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.ok_or_else(|| anyhow!("invalid mtime"))?.duration_since(UNIX_EPOCH)?.as_micros();
|
||||
Ok(modified >= self.last.load(Ordering::Relaxed) as u128)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{fs::{FileType, Metadata}, ops::Deref, time::SystemTime};
|
||||
use std::{ffi::OsStr, fs::{FileType, Metadata}, ops::Deref, time::SystemTime};
|
||||
|
||||
use yazi_macro::{unix_either, win_either};
|
||||
use yazi_shared::url::Url;
|
||||
|
|
@ -47,11 +47,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 +57,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 attached = 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() {
|
||||
if cha.is_link() {
|
||||
attached |= ChaKind::ORPHAN;
|
||||
}
|
||||
|
||||
Self::from_bare(&meta).attach(attached)
|
||||
cha.attach(attached)
|
||||
}
|
||||
|
||||
pub fn from_dummy<'a, U>(_url: U, ft: Option<FileType>) -> Self
|
||||
|
|
|
|||
|
|
@ -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,16 +17,16 @@ 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() {
|
||||
{
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
if _name.as_bytes().starts_with(b".") {
|
||||
me |= Self::HIDDEN;
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<()>
|
||||
|
|
|
|||
|
|
@ -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>>,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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!() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,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 +122,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>,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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>>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue