mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: size calculator for remote file systems
This commit is contained in:
parent
a3fc9a0ec7
commit
0abfc3c5f1
28 changed files with 476 additions and 348 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{ops::Deref, time::{Duration, SystemTime, UNIX_EPOCH}};
|
use std::{ops::Deref, time::{Duration, SystemTime, UNIX_EPOCH}};
|
||||||
|
|
||||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, UserDataMethods};
|
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, UserDataMethods};
|
||||||
use yazi_fs::cha::ChaKind;
|
use yazi_fs::cha::{ChaKind, ChaMode};
|
||||||
|
|
||||||
#[derive(Clone, Copy, FromLua)]
|
#[derive(Clone, Copy, FromLua)]
|
||||||
pub struct Cha(pub yazi_fs::cha::Cha);
|
pub struct Cha(pub yazi_fs::cha::Cha);
|
||||||
|
|
@ -25,11 +25,15 @@ impl Cha {
|
||||||
lua.globals().raw_set(
|
lua.globals().raw_set(
|
||||||
"Cha",
|
"Cha",
|
||||||
lua.create_function(|lua, t: Table| {
|
lua.create_function(|lua, t: Table| {
|
||||||
let kind =
|
let kind = ChaKind::from_bits(t.raw_get("kind").unwrap_or_default())
|
||||||
ChaKind::from_bits(t.raw_get("kind")?).ok_or_else(|| "Invalid kind".into_lua_err())?;
|
.ok_or_else(|| "Invalid kind".into_lua_err())?;
|
||||||
|
|
||||||
|
let mode =
|
||||||
|
ChaMode::from_bits(t.raw_get("mode")?).ok_or_else(|| "Invalid mode".into_lua_err())?;
|
||||||
|
|
||||||
Self(yazi_fs::cha::Cha {
|
Self(yazi_fs::cha::Cha {
|
||||||
kind,
|
kind,
|
||||||
|
mode,
|
||||||
len: t.raw_get("len").unwrap_or_default(),
|
len: t.raw_get("len").unwrap_or_default(),
|
||||||
atime: parse_time(t.raw_get("atime").ok())?,
|
atime: parse_time(t.raw_get("atime").ok())?,
|
||||||
btime: parse_time(t.raw_get("btime").ok())?,
|
btime: parse_time(t.raw_get("btime").ok())?,
|
||||||
|
|
@ -37,8 +41,6 @@ impl Cha {
|
||||||
ctime: parse_time(t.raw_get("ctime").ok())?,
|
ctime: parse_time(t.raw_get("ctime").ok())?,
|
||||||
mtime: parse_time(t.raw_get("mtime").ok())?,
|
mtime: parse_time(t.raw_get("mtime").ok())?,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mode: t.raw_get("mode").unwrap_or_default(),
|
|
||||||
#[cfg(unix)]
|
|
||||||
dev: t.raw_get("dev").unwrap_or_default(),
|
dev: t.raw_get("dev").unwrap_or_default(),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
uid: t.raw_get("uid").unwrap_or_default(),
|
uid: t.raw_get("uid").unwrap_or_default(),
|
||||||
|
|
@ -55,6 +57,7 @@ impl Cha {
|
||||||
|
|
||||||
impl UserData for Cha {
|
impl UserData for Cha {
|
||||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||||
|
fields.add_field_method_get("mode", |_, me| Ok(me.mode.bits()));
|
||||||
fields.add_field_method_get("is_dir", |_, me| Ok(me.is_dir()));
|
fields.add_field_method_get("is_dir", |_, me| Ok(me.is_dir()));
|
||||||
fields.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
|
fields.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
|
||||||
fields.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
|
fields.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
|
||||||
|
|
@ -70,7 +73,6 @@ impl UserData for Cha {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
fields.add_field_method_get("mode", |_, me| Ok(me.is_dummy().not().then_some(me.mode)));
|
|
||||||
fields.add_field_method_get("dev", |_, me| Ok(me.is_dummy().not().then_some(me.dev)));
|
fields.add_field_method_get("dev", |_, me| Ok(me.is_dummy().not().then_some(me.dev)));
|
||||||
fields.add_field_method_get("uid", |_, me| Ok(me.is_dummy().not().then_some(me.uid)));
|
fields.add_field_method_get("uid", |_, me| Ok(me.is_dummy().not().then_some(me.uid)));
|
||||||
fields.add_field_method_get("gid", |_, me| Ok(me.is_dummy().not().then_some(me.gid)));
|
fields.add_field_method_get("gid", |_, me| Ok(me.is_dummy().not().then_some(me.gid)));
|
||||||
|
|
@ -94,12 +96,12 @@ impl UserData for Cha {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||||
methods.add_method("perm", |_, _me, ()| {
|
methods.add_method("perm", |lua, _me, ()| {
|
||||||
Ok(
|
Ok(
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
Some(yazi_fs::permissions(_me.mode, _me.is_dummy())),
|
lua.create_string(_me.mode.permissions(_me.is_dummy())),
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
None::<String>,
|
Ok(mlua::Value::Nil),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::{mem, ops::Deref, sync::atomic::{AtomicU64, Ordering}, time::UNIX_EPOCH
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufWriter};
|
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter};
|
||||||
use yazi_boot::BOOT;
|
use yazi_boot::BOOT;
|
||||||
use yazi_fs::provider::local::{Gate, Local};
|
use yazi_fs::provider::local::{Gate, Local};
|
||||||
use yazi_shared::{RoCell, timestamp_us};
|
use yazi_shared::{RoCell, timestamp_us};
|
||||||
|
|
@ -79,7 +79,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load(&self) -> Result<()> {
|
async fn load(&self) -> Result<()> {
|
||||||
let mut file = Local::open(BOOT.state_dir.join(".dds")).await?.reader();
|
let mut file = BufReader::new(Local::open(BOOT.state_dir.join(".dds")).await?);
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
|
|
||||||
let mut inner = HashMap::new();
|
let mut inner = HashMap::new();
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
use std::{fs::{FileType, Metadata}, time::SystemTime};
|
use std::{fs::{FileType, Metadata}, ops::Deref, time::SystemTime};
|
||||||
|
|
||||||
use yazi_macro::{unix_either, win_either};
|
use yazi_macro::{unix_either, win_either};
|
||||||
use yazi_shared::url::{Url, UrlBuf};
|
use yazi_shared::url::{Url, UrlBuf};
|
||||||
|
|
||||||
use super::ChaKind;
|
use super::ChaKind;
|
||||||
use crate::provider;
|
use crate::{cha::ChaMode, provider};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct Cha {
|
pub struct Cha {
|
||||||
pub kind: ChaKind,
|
pub kind: ChaKind,
|
||||||
|
pub mode: ChaMode,
|
||||||
pub len: u64,
|
pub len: u64,
|
||||||
pub atime: Option<SystemTime>,
|
pub atime: Option<SystemTime>,
|
||||||
pub btime: Option<SystemTime>,
|
pub btime: Option<SystemTime>,
|
||||||
|
|
@ -16,21 +17,26 @@ pub struct Cha {
|
||||||
pub ctime: Option<SystemTime>,
|
pub ctime: Option<SystemTime>,
|
||||||
pub mtime: Option<SystemTime>,
|
pub mtime: Option<SystemTime>,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub mode: libc::mode_t,
|
|
||||||
#[cfg(unix)]
|
|
||||||
pub dev: libc::dev_t,
|
pub dev: libc::dev_t,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub uid: libc::uid_t,
|
pub uid: u32,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub gid: libc::gid_t,
|
pub gid: u32,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub nlink: libc::nlink_t,
|
pub nlink: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Cha {
|
||||||
|
type Target = ChaMode;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target { &self.mode }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Cha {
|
impl Default for Cha {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
kind: ChaKind::DUMMY,
|
kind: ChaKind::DUMMY,
|
||||||
|
mode: ChaMode::empty(),
|
||||||
len: 0,
|
len: 0,
|
||||||
atime: None,
|
atime: None,
|
||||||
btime: None,
|
btime: None,
|
||||||
|
|
@ -38,8 +44,6 @@ impl Default for Cha {
|
||||||
ctime: None,
|
ctime: None,
|
||||||
mtime: None,
|
mtime: None,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mode: 0,
|
|
||||||
#[cfg(unix)]
|
|
||||||
dev: 0,
|
dev: 0,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
uid: 0,
|
uid: 0,
|
||||||
|
|
@ -54,7 +58,7 @@ impl Default for Cha {
|
||||||
impl Cha {
|
impl Cha {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<'a>(url: impl Into<Url<'a>>, meta: Metadata) -> Self {
|
pub fn new<'a>(url: impl Into<Url<'a>>, meta: Metadata) -> Self {
|
||||||
Self::from_just_meta(&meta).attach(ChaKind::hidden(url, &meta))
|
Self::from_bare_meta(&meta).attach(ChaKind::hidden(url, &meta))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -75,12 +79,12 @@ impl Cha {
|
||||||
attached |= ChaKind::ORPHAN;
|
attached |= ChaKind::ORPHAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::from_just_meta(&meta).attach(attached)
|
Self::from_bare_meta(&meta).attach(attached)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_dummy(_url: &UrlBuf, ft: Option<FileType>) -> Self {
|
pub fn from_dummy(_url: &UrlBuf, ft: Option<FileType>) -> Self {
|
||||||
let mut me = ft.map(Self::from_half_ft).unwrap_or_default();
|
let mut me = ft.map(Self::from_bare_ft).unwrap_or_default();
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
if _url.urn().is_hidden() {
|
if _url.urn().is_hidden() {
|
||||||
me.kind |= ChaKind::HIDDEN;
|
me.kind |= ChaKind::HIDDEN;
|
||||||
|
|
@ -88,61 +92,74 @@ impl Cha {
|
||||||
me
|
me
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_half_ft(ft: FileType) -> Self {
|
fn from_bare_ft(ft: FileType) -> Self {
|
||||||
let mut kind = ChaKind::DUMMY;
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let mode = {
|
let mode = {
|
||||||
use std::os::unix::fs::FileTypeExt;
|
use std::os::unix::fs::FileTypeExt;
|
||||||
if ft.is_dir() {
|
if ft.is_file() {
|
||||||
kind |= ChaKind::DIR;
|
ChaMode::T_FILE
|
||||||
libc::S_IFDIR
|
} else if ft.is_dir() {
|
||||||
|
ChaMode::T_DIR
|
||||||
} else if ft.is_symlink() {
|
} else if ft.is_symlink() {
|
||||||
kind |= ChaKind::LINK;
|
ChaMode::T_LINK
|
||||||
libc::S_IFLNK
|
|
||||||
} else if ft.is_block_device() {
|
} else if ft.is_block_device() {
|
||||||
libc::S_IFBLK
|
ChaMode::T_BLOCK
|
||||||
} else if ft.is_char_device() {
|
} else if ft.is_char_device() {
|
||||||
libc::S_IFCHR
|
ChaMode::T_CHAR
|
||||||
} else if ft.is_fifo() {
|
|
||||||
libc::S_IFIFO
|
|
||||||
} else if ft.is_socket() {
|
} else if ft.is_socket() {
|
||||||
libc::S_IFSOCK
|
ChaMode::T_SOCK
|
||||||
|
} else if ft.is_fifo() {
|
||||||
|
ChaMode::T_FIFO
|
||||||
} else {
|
} else {
|
||||||
0
|
ChaMode::empty()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
let mode = {
|
||||||
if ft.is_dir() {
|
if ft.is_file() {
|
||||||
kind |= ChaKind::DIR;
|
ChaMode::T_FILE
|
||||||
|
} else if ft.is_dir() {
|
||||||
|
ChaMode::T_DIR
|
||||||
} else if ft.is_symlink() {
|
} else if ft.is_symlink() {
|
||||||
kind |= ChaKind::LINK;
|
ChaMode::T_LINK
|
||||||
|
} else {
|
||||||
|
ChaMode::empty()
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
Self {
|
let kind = ChaKind::DUMMY
|
||||||
kind,
|
| if mode.contains(ChaMode::T_LINK) { ChaKind::LINK } else { ChaKind::empty() };
|
||||||
#[cfg(unix)]
|
|
||||||
mode,
|
Self { kind, mode, ..Default::default() }
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_just_meta(m: &Metadata) -> Self {
|
fn from_bare_meta(m: &Metadata) -> Self {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::{os::unix::{fs::MetadataExt, prelude::PermissionsExt}, time::{Duration, UNIX_EPOCH}};
|
use std::{os::unix::fs::MetadataExt, time::{Duration, UNIX_EPOCH}};
|
||||||
|
|
||||||
let mut kind = ChaKind::empty();
|
#[cfg(unix)]
|
||||||
if m.is_dir() {
|
let mode = {
|
||||||
kind |= ChaKind::DIR;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
} else if m.is_symlink() {
|
ChaMode::from_bits_retain(m.permissions().mode() as u16)
|
||||||
kind |= ChaKind::LINK;
|
};
|
||||||
}
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let mode = {
|
||||||
|
if m.is_file() {
|
||||||
|
ChaMode::T_FILE
|
||||||
|
} else if m.is_dir() {
|
||||||
|
ChaMode::T_DIR
|
||||||
|
} else if m.is_symlink() {
|
||||||
|
ChaMode::T_LINK
|
||||||
|
} else {
|
||||||
|
ChaMode::empty()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
kind,
|
kind: ChaKind::empty(),
|
||||||
|
mode,
|
||||||
len: m.len(),
|
len: m.len(),
|
||||||
atime: m.accessed().ok(),
|
atime: m.accessed().ok(),
|
||||||
btime: m.created().ok(),
|
btime: m.created().ok(),
|
||||||
|
|
@ -150,8 +167,6 @@ impl Cha {
|
||||||
ctime: UNIX_EPOCH.checked_add(Duration::new(m.ctime() as u64, m.ctime_nsec() as u32)),
|
ctime: UNIX_EPOCH.checked_add(Duration::new(m.ctime() as u64, m.ctime_nsec() as u32)),
|
||||||
mtime: m.modified().ok(),
|
mtime: m.modified().ok(),
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mode: m.permissions().mode() as _,
|
|
||||||
#[cfg(unix)]
|
|
||||||
dev: m.dev() as _,
|
dev: m.dev() as _,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
uid: m.uid() as _,
|
uid: m.uid() as _,
|
||||||
|
|
@ -180,9 +195,6 @@ impl Cha {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cha {
|
impl Cha {
|
||||||
#[inline]
|
|
||||||
pub const fn is_dir(&self) -> bool { self.kind.contains(ChaKind::DIR) }
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_hidden(&self) -> bool {
|
pub const fn is_hidden(&self) -> bool {
|
||||||
win_either!(
|
win_either!(
|
||||||
|
|
@ -191,38 +203,9 @@ impl Cha {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub const fn is_link(&self) -> bool { self.kind.contains(ChaKind::LINK) }
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) }
|
pub const fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_dummy(&self) -> bool { self.kind.contains(ChaKind::DUMMY) }
|
pub const fn is_dummy(&self) -> bool { self.kind.contains(ChaKind::DUMMY) }
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub const fn is_block(&self) -> bool {
|
|
||||||
unix_either!(self.mode & libc::S_IFMT == libc::S_IFBLK, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub const fn is_char(&self) -> bool {
|
|
||||||
unix_either!(self.mode & libc::S_IFMT == libc::S_IFCHR, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub const fn is_fifo(&self) -> bool {
|
|
||||||
unix_either!(self.mode & libc::S_IFMT == libc::S_IFIFO, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub const fn is_sock(&self) -> bool {
|
|
||||||
unix_either!(self.mode & libc::S_IFMT == libc::S_IFSOCK, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub const fn is_exec(&self) -> bool { unix_either!(self.mode & libc::S_IXUSR != 0, false) }
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub const fn is_sticky(&self) -> bool { unix_either!(self.mode & libc::S_ISVTX != 0, false) }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,13 @@ use yazi_shared::url::Url;
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct ChaKind: u8 {
|
pub struct ChaKind: u8 {
|
||||||
const DIR = 0b00000001;
|
const HIDDEN = 0b0000_0001;
|
||||||
|
const SYSTEM = 0b0000_0010;
|
||||||
|
|
||||||
const HIDDEN = 0b00000010;
|
const LINK = 0b0000_0100;
|
||||||
const LINK = 0b00000100;
|
const ORPHAN = 0b0000_1000;
|
||||||
const ORPHAN = 0b00001000;
|
|
||||||
|
|
||||||
const DUMMY = 0b00010000;
|
const DUMMY = 0b0001_0000;
|
||||||
#[cfg(windows)]
|
|
||||||
const SYSTEM = 0b00100000;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
yazi_macro::mod_flat!(cha kind);
|
yazi_macro::mod_flat!(cha kind mode);
|
||||||
|
|
|
||||||
120
yazi-fs/src/cha/mode.rs
Normal file
120
yazi-fs/src/cha/mode.rs
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
use bitflags::bitflags;
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
|
pub struct ChaMode: u16 {
|
||||||
|
// File type
|
||||||
|
const T_MASK = 0b1111_0000_0000_0000;
|
||||||
|
const T_SOCK = 0b1100_0000_0000_0000;
|
||||||
|
const T_LINK = 0b1010_0000_0000_0000;
|
||||||
|
const T_FILE = 0b1000_0000_0000_0000;
|
||||||
|
const T_BLOCK = 0b0110_0000_0000_0000;
|
||||||
|
const T_DIR = 0b0100_0000_0000_0000;
|
||||||
|
const T_CHAR = 0b0010_0000_0000_0000;
|
||||||
|
const T_FIFO = 0b0001_0000_0000_0000;
|
||||||
|
// Special
|
||||||
|
const S_SUID = 0b0000_1000_0000_0000;
|
||||||
|
const S_SGID = 0b0000_0100_0000_0000;
|
||||||
|
const S_STICKY = 0b0000_0010_0000_0000;
|
||||||
|
// User
|
||||||
|
const U_MASK = 0b0000_0001_1100_0000;
|
||||||
|
const U_READ = 0b0000_0001_0000_0000;
|
||||||
|
const U_WRITE = 0b0000_0000_1000_0000;
|
||||||
|
const U_EXEC = 0b0000_0000_0100_0000;
|
||||||
|
// Group
|
||||||
|
const G_MASK = 0b0000_0000_0011_1000;
|
||||||
|
const G_READ = 0b0000_0000_0010_0000;
|
||||||
|
const G_WRITE = 0b0000_0000_0001_0000;
|
||||||
|
const G_EXEC = 0b0000_0000_0000_1000;
|
||||||
|
// Others
|
||||||
|
const O_MASK = 0b0000_0000_0000_0111;
|
||||||
|
const O_READ = 0b0000_0000_0000_0100;
|
||||||
|
const O_WRITE = 0b0000_0000_0000_0010;
|
||||||
|
const O_EXEC = 0b0000_0000_0000_0001;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaMode {
|
||||||
|
#[inline]
|
||||||
|
pub fn r#type(self) -> Self { self & Self::T_MASK }
|
||||||
|
|
||||||
|
// Convert a file mode to a string representation
|
||||||
|
#[cfg(unix)]
|
||||||
|
#[allow(clippy::collapsible_else_if)]
|
||||||
|
pub fn permissions(self, dummy: bool) -> [u8; 10] {
|
||||||
|
let mut s = *b"-?????????";
|
||||||
|
|
||||||
|
// File type
|
||||||
|
s[0] = match self.r#type() {
|
||||||
|
Self::T_DIR => b'd',
|
||||||
|
Self::T_LINK => b'l',
|
||||||
|
Self::T_BLOCK => b'b',
|
||||||
|
Self::T_CHAR => b'c',
|
||||||
|
Self::T_SOCK => b's',
|
||||||
|
Self::T_FIFO => b'p',
|
||||||
|
_ => b'-',
|
||||||
|
};
|
||||||
|
if dummy {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// User
|
||||||
|
s[1] = if self.contains(Self::U_READ) { b'r' } else { b'-' };
|
||||||
|
s[2] = if self.contains(Self::U_WRITE) { b'w' } else { b'-' };
|
||||||
|
s[3] = if self.contains(Self::U_EXEC) {
|
||||||
|
if self.contains(Self::S_SUID) { b's' } else { b'x' }
|
||||||
|
} else {
|
||||||
|
if self.contains(Self::S_SUID) { b'S' } else { b'-' }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Group
|
||||||
|
s[4] = if self.contains(Self::G_READ) { b'r' } else { b'-' };
|
||||||
|
s[5] = if self.contains(Self::G_WRITE) { b'w' } else { b'-' };
|
||||||
|
s[6] = if self.contains(Self::G_EXEC) {
|
||||||
|
if self.contains(Self::S_SGID) { b's' } else { b'x' }
|
||||||
|
} else {
|
||||||
|
if self.contains(Self::S_SGID) { b'S' } else { b'-' }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Others
|
||||||
|
s[7] = if self.contains(Self::O_READ) { b'r' } else { b'-' };
|
||||||
|
s[8] = if self.contains(Self::O_WRITE) { b'w' } else { b'-' };
|
||||||
|
s[9] = if self.contains(Self::O_EXEC) {
|
||||||
|
if self.contains(Self::S_STICKY) { b't' } else { b'x' }
|
||||||
|
} else {
|
||||||
|
if self.contains(Self::S_STICKY) { b'T' } else { b'-' }
|
||||||
|
};
|
||||||
|
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChaMode {
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_file(self) -> bool { self.contains(Self::T_FILE) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_dir(self) -> bool { self.contains(Self::T_DIR) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_link(&self) -> bool { self.contains(Self::T_LINK) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_block(&self) -> bool { self.contains(Self::T_BLOCK) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_char(&self) -> bool { self.contains(Self::T_CHAR) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_sock(&self) -> bool { self.contains(Self::T_SOCK) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_fifo(&self) -> bool { self.contains(Self::T_FIFO) }
|
||||||
|
|
||||||
|
// TODO: deprecate
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_exec(&self) -> bool { self.contains(Self::U_EXEC) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_sticky(&self) -> bool { self.contains(Self::S_STICKY) }
|
||||||
|
}
|
||||||
|
|
@ -94,59 +94,6 @@ pub async fn remove_dir_clean(dir: &UrlBuf) {
|
||||||
provider::remove_dir(dir).await.ok();
|
provider::remove_dir(dir).await.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert a file mode to a string representation
|
|
||||||
#[cfg(unix)]
|
|
||||||
#[allow(clippy::collapsible_else_if)]
|
|
||||||
pub fn permissions(m: libc::mode_t, dummy: bool) -> String {
|
|
||||||
use libc::{S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFSOCK, S_IRGRP, S_IROTH, S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR};
|
|
||||||
let mut s = String::with_capacity(10);
|
|
||||||
|
|
||||||
// Filetype
|
|
||||||
s.push(match m & S_IFMT {
|
|
||||||
S_IFBLK => 'b',
|
|
||||||
S_IFCHR => 'c',
|
|
||||||
S_IFDIR => 'd',
|
|
||||||
S_IFIFO => 'p',
|
|
||||||
S_IFLNK => 'l',
|
|
||||||
S_IFSOCK => 's',
|
|
||||||
_ => '-',
|
|
||||||
});
|
|
||||||
|
|
||||||
if dummy {
|
|
||||||
s.push_str("?????????");
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Owner
|
|
||||||
s.push(if m & S_IRUSR != 0 { 'r' } else { '-' });
|
|
||||||
s.push(if m & S_IWUSR != 0 { 'w' } else { '-' });
|
|
||||||
s.push(if m & S_IXUSR != 0 {
|
|
||||||
if m & S_ISUID != 0 { 's' } else { 'x' }
|
|
||||||
} else {
|
|
||||||
if m & S_ISUID != 0 { 'S' } else { '-' }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Group
|
|
||||||
s.push(if m & S_IRGRP != 0 { 'r' } else { '-' });
|
|
||||||
s.push(if m & S_IWGRP != 0 { 'w' } else { '-' });
|
|
||||||
s.push(if m & S_IXGRP != 0 {
|
|
||||||
if m & S_ISGID != 0 { 's' } else { 'x' }
|
|
||||||
} else {
|
|
||||||
if m & S_ISGID != 0 { 'S' } else { '-' }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Other
|
|
||||||
s.push(if m & S_IROTH != 0 { 'r' } else { '-' });
|
|
||||||
s.push(if m & S_IWOTH != 0 { 'w' } else { '-' });
|
|
||||||
s.push(if m & S_IXOTH != 0 {
|
|
||||||
if m & S_ISVTX != 0 { 't' } else { 'x' }
|
|
||||||
} else {
|
|
||||||
if m & S_ISVTX != 0 { 'T' } else { '-' }
|
|
||||||
});
|
|
||||||
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the max common root in a list of urls
|
// Find the max common root in a list of urls
|
||||||
// e.g. /a/b/c, /a/b/d -> /a/b
|
// e.g. /a/b/c, /a/b/d -> /a/b
|
||||||
// /aa/bb/cc, /aa/dd/ee -> /aa
|
// /aa/bb/cc, /aa/dd/ee -> /aa
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
yazi_macro::mod_pub!(cha mounts provider path);
|
yazi_macro::mod_pub!(cha mounts provider path);
|
||||||
|
|
||||||
yazi_macro::mod_flat!(calculator cwd file files filter fns op sorter sorting stage xdg);
|
yazi_macro::mod_flat!(cwd file files filter fns op sorter sorting stage xdg);
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
CWD.init(<_>::default());
|
CWD.init(<_>::default());
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
// --- BufRead
|
|
||||||
pub trait BufRead: tokio::io::AsyncRead + Send {}
|
|
||||||
|
|
||||||
impl<T: tokio::io::AsyncRead + Send> BufRead for T {}
|
|
||||||
|
|
||||||
// --- BufReadSync
|
|
||||||
pub trait BufReadSync: std::io::BufRead + std::io::Seek + Send {}
|
|
||||||
|
|
||||||
impl<T: std::io::BufRead + std::io::Seek + Send> BufReadSync for T {}
|
|
||||||
81
yazi-fs/src/provider/calculator.rs
Normal file
81
yazi-fs/src/provider/calculator.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
use std::{collections::VecDeque, io, time::{Duration, Instant}};
|
||||||
|
|
||||||
|
use yazi_shared::{Either, url::{Url, UrlBuf}};
|
||||||
|
|
||||||
|
use crate::provider::{self, ReadDir};
|
||||||
|
|
||||||
|
pub enum SizeCalculator {
|
||||||
|
File(Option<u64>),
|
||||||
|
Dir(VecDeque<Either<UrlBuf, ReadDir>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SizeCalculator {
|
||||||
|
pub async fn new<'a, U>(url: U) -> io::Result<Self>
|
||||||
|
where
|
||||||
|
U: Into<Url<'a>>,
|
||||||
|
{
|
||||||
|
let url: Url = url.into();
|
||||||
|
let meta = provider::symlink_metadata(url).await?;
|
||||||
|
Ok(if meta.is_dir() {
|
||||||
|
Self::Dir(VecDeque::from([Either::Left(url.to_owned())]))
|
||||||
|
} else {
|
||||||
|
Self::File(Some(meta.len()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn total<'a, U>(url: U) -> io::Result<u64>
|
||||||
|
where
|
||||||
|
U: Into<Url<'a>>,
|
||||||
|
{
|
||||||
|
let mut it = Self::new(url).await?;
|
||||||
|
let mut total = 0;
|
||||||
|
while let Some(n) = it.next().await? {
|
||||||
|
total += n;
|
||||||
|
}
|
||||||
|
Ok(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn next(&mut self) -> io::Result<Option<u64>> {
|
||||||
|
Ok(match self {
|
||||||
|
Self::File(size) => size.take(),
|
||||||
|
Self::Dir(buf) => Self::next_chunk(buf).await,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn next_chunk(buf: &mut VecDeque<Either<UrlBuf, ReadDir>>) -> Option<u64> {
|
||||||
|
let (mut i, mut size, now) = (0, 0, Instant::now());
|
||||||
|
macro_rules! pop_and_continue {
|
||||||
|
() => {{
|
||||||
|
buf.pop_front();
|
||||||
|
if buf.is_empty() {
|
||||||
|
return Some(size);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
while i < 2000 && now.elapsed() < Duration::from_millis(100) {
|
||||||
|
i += 1;
|
||||||
|
let front = buf.front_mut()?;
|
||||||
|
|
||||||
|
if let Either::Left(p) = front {
|
||||||
|
*front = match provider::read_dir(p).await {
|
||||||
|
Ok(it) => Either::Right(it),
|
||||||
|
Err(_) => pop_and_continue!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(Some(ent)) = front.right_mut()?.next_entry().await else {
|
||||||
|
pop_and_continue!();
|
||||||
|
};
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -33,36 +33,3 @@ impl DirEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- DirEntrySync
|
|
||||||
pub enum DirEntrySync {
|
|
||||||
Local(super::local::DirEntrySync),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DirEntrySync {
|
|
||||||
#[must_use]
|
|
||||||
pub fn url(&self) -> UrlBuf {
|
|
||||||
match self {
|
|
||||||
Self::Local(local) => local.url(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn file_name(&self) -> OsString {
|
|
||||||
match self {
|
|
||||||
Self::Local(local) => local.file_name(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn metadata(&self) -> io::Result<std::fs::Metadata> {
|
|
||||||
match self {
|
|
||||||
Self::Local(local) => local.metadata(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file_type(&self) -> io::Result<std::fs::FileType> {
|
|
||||||
match self {
|
|
||||||
Self::Local(local) => local.file_type(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
use std::{collections::VecDeque, future::poll_fn, io, mem, pin::Pin, task::{Poll, ready}, time::{Duration, Instant}};
|
use std::{collections::VecDeque, future::poll_fn, io, mem, path::{Path, PathBuf}, pin::Pin, task::{Poll, ready}, time::{Duration, Instant}};
|
||||||
|
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use yazi_shared::{Either, url::UrlBuf};
|
use yazi_shared::Either;
|
||||||
|
|
||||||
use crate::provider::{self, ReadDirSync};
|
type Task = Either<PathBuf, std::fs::ReadDir>;
|
||||||
|
|
||||||
type Task = Either<UrlBuf, ReadDirSync>;
|
|
||||||
|
|
||||||
pub enum SizeCalculator {
|
pub enum SizeCalculator {
|
||||||
Idle((VecDeque<Task>, Option<u64>)),
|
Idle((VecDeque<Task>, Option<u64>)),
|
||||||
|
|
@ -13,23 +11,23 @@ pub enum SizeCalculator {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SizeCalculator {
|
impl SizeCalculator {
|
||||||
pub async fn new(url: &UrlBuf) -> io::Result<Self> {
|
pub async fn new(path: &Path) -> io::Result<Self> {
|
||||||
let u = url.to_owned();
|
let p = path.to_owned();
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
let meta = provider::symlink_metadata_sync(&u)?;
|
let meta = std::fs::symlink_metadata(&p)?;
|
||||||
if !meta.is_dir() {
|
if !meta.is_dir() {
|
||||||
return Ok(Self::Idle((VecDeque::new(), Some(meta.len()))));
|
return Ok(Self::Idle((VecDeque::new(), Some(meta.len()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buf = VecDeque::from([Either::Right(provider::read_dir_sync(&u)?)]);
|
let mut buf = VecDeque::from([Either::Right(std::fs::read_dir(&p)?)]);
|
||||||
let size = Self::next_chunk(&mut buf);
|
let size = Self::next_chunk(&mut buf);
|
||||||
Ok(Self::Idle((buf, size)))
|
Ok(Self::Idle((buf, size)))
|
||||||
})
|
})
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn total(url: &UrlBuf) -> io::Result<u64> {
|
pub async fn total(path: &Path) -> io::Result<u64> {
|
||||||
let mut it = Self::new(url).await?;
|
let mut it = Self::new(path).await?;
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
while let Some(n) = it.next().await? {
|
while let Some(n) = it.next().await? {
|
||||||
total += n;
|
total += n;
|
||||||
|
|
@ -63,7 +61,7 @@ impl SizeCalculator {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_chunk(buf: &mut VecDeque<Either<UrlBuf, ReadDirSync>>) -> Option<u64> {
|
fn next_chunk(buf: &mut VecDeque<Either<PathBuf, std::fs::ReadDir>>) -> Option<u64> {
|
||||||
let (mut i, mut size, now) = (0, 0, Instant::now());
|
let (mut i, mut size, now) = (0, 0, Instant::now());
|
||||||
macro_rules! pop_and_continue {
|
macro_rules! pop_and_continue {
|
||||||
() => {{
|
() => {{
|
||||||
|
|
@ -79,8 +77,8 @@ impl SizeCalculator {
|
||||||
i += 1;
|
i += 1;
|
||||||
let front = buf.front_mut()?;
|
let front = buf.front_mut()?;
|
||||||
|
|
||||||
if let Either::Left(u) = front {
|
if let Either::Left(p) = front {
|
||||||
*front = match provider::read_dir_sync(u) {
|
*front = match std::fs::read_dir(p) {
|
||||||
Ok(it) => Either::Right(it),
|
Ok(it) => Either::Right(it),
|
||||||
Err(_) => pop_and_continue!(),
|
Err(_) => pop_and_continue!(),
|
||||||
};
|
};
|
||||||
|
|
@ -93,7 +91,7 @@ impl SizeCalculator {
|
||||||
let Ok(ent) = next else { continue };
|
let Ok(ent) = next else { continue };
|
||||||
let Ok(ft) = ent.file_type() else { continue };
|
let Ok(ft) = ent.file_type() else { continue };
|
||||||
if ft.is_dir() {
|
if ft.is_dir() {
|
||||||
buf.push_back(Either::Left(ent.url()));
|
buf.push_back(Either::Left(ent.path()));
|
||||||
} else if let Ok(meta) = ent.metadata() {
|
} else if let Ok(meta) = ent.metadata() {
|
||||||
size += meta.len();
|
size += meta.len();
|
||||||
}
|
}
|
||||||
|
|
@ -22,25 +22,3 @@ impl DirEntry {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn url(&self) -> UrlBuf { self.0.path().into() }
|
pub fn url(&self) -> UrlBuf { self.0.path().into() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- DirEntrySync
|
|
||||||
pub struct DirEntrySync(std::fs::DirEntry);
|
|
||||||
|
|
||||||
impl Deref for DirEntrySync {
|
|
||||||
type Target = std::fs::DirEntry;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target { &self.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::fs::DirEntry> for DirEntrySync {
|
|
||||||
fn from(value: std::fs::DirEntry) -> Self { Self(value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DirEntrySync> for crate::provider::DirEntrySync {
|
|
||||||
fn from(value: DirEntrySync) -> Self { Self::Local(value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DirEntrySync {
|
|
||||||
#[must_use]
|
|
||||||
pub fn url(&self) -> UrlBuf { self.0.path().into() }
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{io, path::{Path, PathBuf}};
|
use std::{io, path::{Path, PathBuf}};
|
||||||
|
|
||||||
use crate::{cha::Cha, provider::local::{Gate, ReadDir, ReadDirSync, RwFile}};
|
use crate::{cha::Cha, provider::local::{Gate, ReadDir, RwFile}};
|
||||||
|
|
||||||
pub struct Local;
|
pub struct Local;
|
||||||
|
|
||||||
|
|
@ -145,14 +145,6 @@ impl Local {
|
||||||
tokio::fs::read_dir(path).await.map(Into::into)
|
tokio::fs::read_dir(path).await.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn read_dir_sync<P>(path: P) -> io::Result<ReadDirSync>
|
|
||||||
where
|
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
|
||||||
std::fs::read_dir(path).map(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn read_link<P>(path: P) -> io::Result<PathBuf>
|
pub async fn read_link<P>(path: P) -> io::Result<PathBuf>
|
||||||
where
|
where
|
||||||
|
|
@ -261,14 +253,6 @@ impl Local {
|
||||||
tokio::fs::symlink_metadata(path).await
|
tokio::fs::symlink_metadata(path).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn symlink_metadata_sync<P>(path: P) -> io::Result<std::fs::Metadata>
|
|
||||||
where
|
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
|
||||||
std::fs::symlink_metadata(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn trash<P>(path: P) -> io::Result<()>
|
pub async fn trash<P>(path: P) -> io::Result<()>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
yazi_macro::mod_flat!(casefold dir_entry gate identical local read_dir rw_file);
|
yazi_macro::mod_flat!(calculator casefold dir_entry gate identical local read_dir rw_file);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use super::{DirEntry, DirEntrySync};
|
use super::DirEntry;
|
||||||
|
|
||||||
pub struct ReadDir(tokio::fs::ReadDir);
|
pub struct ReadDir(tokio::fs::ReadDir);
|
||||||
|
|
||||||
|
|
@ -17,22 +17,3 @@ impl ReadDir {
|
||||||
self.0.next_entry().await.map(|entry| entry.map(Into::into))
|
self.0.next_entry().await.map(|entry| entry.map(Into::into))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- ReadDirSync
|
|
||||||
pub struct ReadDirSync(std::fs::ReadDir);
|
|
||||||
|
|
||||||
impl From<std::fs::ReadDir> for ReadDirSync {
|
|
||||||
fn from(value: std::fs::ReadDir) -> Self { Self(value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ReadDirSync> for crate::provider::ReadDirSync {
|
|
||||||
fn from(value: ReadDirSync) -> Self { Self::Local(value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for ReadDirSync {
|
|
||||||
type Item = io::Result<DirEntrySync>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<io::Result<DirEntrySync>> {
|
|
||||||
self.0.next().map(|result| result.map(Into::into))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
use std::{pin::Pin, task::Poll};
|
||||||
|
|
||||||
|
use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
|
||||||
|
|
||||||
pub struct RwFile(tokio::fs::File);
|
pub struct RwFile(tokio::fs::File);
|
||||||
|
|
||||||
impl From<tokio::fs::File> for RwFile {
|
impl From<tokio::fs::File> for RwFile {
|
||||||
|
|
@ -8,11 +12,67 @@ impl From<RwFile> for crate::provider::RwFile {
|
||||||
fn from(value: RwFile) -> Self { Self::Local(value) }
|
fn from(value: RwFile) -> Self { Self::Local(value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<tokio::fs::File> for crate::provider::RwFile {
|
impl AsyncRead for RwFile {
|
||||||
fn from(value: tokio::fs::File) -> Self { RwFile(value).into() }
|
#[inline]
|
||||||
|
fn poll_read(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
buf: &mut tokio::io::ReadBuf<'_>,
|
||||||
|
) -> Poll<std::io::Result<()>> {
|
||||||
|
Pin::new(&mut self.0).poll_read(cx, buf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RwFile {
|
impl AsyncSeek for RwFile {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reader(self) -> tokio::io::BufReader<tokio::fs::File> { tokio::io::BufReader::new(self.0) }
|
fn start_seek(mut self: Pin<&mut Self>, position: std::io::SeekFrom) -> std::io::Result<()> {
|
||||||
|
Pin::new(&mut self.0).start_seek(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll_complete(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
) -> Poll<std::io::Result<u64>> {
|
||||||
|
Pin::new(&mut self.0).poll_complete(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncWrite for RwFile {
|
||||||
|
#[inline]
|
||||||
|
fn poll_write(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
buf: &[u8],
|
||||||
|
) -> Poll<Result<usize, std::io::Error>> {
|
||||||
|
Pin::new(&mut self.0).poll_write(cx, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll_flush(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
) -> Poll<Result<(), std::io::Error>> {
|
||||||
|
Pin::new(&mut self.0).poll_flush(cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll_shutdown(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
) -> Poll<Result<(), std::io::Error>> {
|
||||||
|
Pin::new(&mut self.0).poll_shutdown(cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll_write_vectored(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
bufs: &[std::io::IoSlice<'_>],
|
||||||
|
) -> Poll<Result<usize, std::io::Error>> {
|
||||||
|
Pin::new(&mut self.0).poll_write_vectored(cx, bufs)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_write_vectored(&self) -> bool { self.0.is_write_vectored() }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
yazi_macro::mod_pub!(local sftp);
|
yazi_macro::mod_pub!(local sftp);
|
||||||
|
|
||||||
yazi_macro::mod_flat!(buffer dir_entry provider read_dir rw_file);
|
yazi_macro::mod_flat!(calculator dir_entry provider read_dir rw_file);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::{io, path::{Path, PathBuf}};
|
||||||
|
|
||||||
use yazi_shared::url::{Url, UrlBuf};
|
use yazi_shared::url::{Url, UrlBuf};
|
||||||
|
|
||||||
use crate::{cha::Cha, provider::{ReadDir, ReadDirSync, RwFile, local::{self, Local}}};
|
use crate::{cha::Cha, provider::{ReadDir, RwFile, local::{self, Local}}};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cache<'a, U>(url: U) -> Option<PathBuf>
|
pub fn cache<'a, U>(url: U) -> Option<PathBuf>
|
||||||
|
|
@ -12,6 +12,19 @@ where
|
||||||
if let Some(path) = url.into().as_path() { Local::cache(path) } else { None }
|
if let Some(path) = url.into().as_path() { Local::cache(path) } else { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub async fn calculate<'a, U>(url: U) -> io::Result<u64>
|
||||||
|
where
|
||||||
|
U: Into<Url<'a>>,
|
||||||
|
{
|
||||||
|
let url: Url = url.into();
|
||||||
|
if let Some(path) = url.as_path() {
|
||||||
|
local::SizeCalculator::total(path).await
|
||||||
|
} else {
|
||||||
|
super::SizeCalculator::total(url).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn canonicalize<'a, U>(url: U) -> io::Result<UrlBuf>
|
pub async fn canonicalize<'a, U>(url: U) -> io::Result<UrlBuf>
|
||||||
where
|
where
|
||||||
|
|
@ -156,18 +169,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn read_dir_sync<'a, U>(url: U) -> io::Result<ReadDirSync>
|
|
||||||
where
|
|
||||||
U: Into<Url<'a>>,
|
|
||||||
{
|
|
||||||
if let Some(path) = url.into().as_path() {
|
|
||||||
Local::read_dir_sync(path).map(Into::into)
|
|
||||||
} else {
|
|
||||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn read_link<'a, U>(url: U) -> io::Result<PathBuf>
|
pub async fn read_link<'a, U>(url: U) -> io::Result<PathBuf>
|
||||||
where
|
where
|
||||||
|
|
@ -278,18 +279,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn symlink_metadata_sync<'a, U>(url: U) -> io::Result<std::fs::Metadata>
|
|
||||||
where
|
|
||||||
U: Into<Url<'a>>,
|
|
||||||
{
|
|
||||||
if let Some(path) = url.into().as_path() {
|
|
||||||
Local::symlink_metadata_sync(path)
|
|
||||||
} else {
|
|
||||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn trash<'a, U>(url: U) -> io::Result<()>
|
pub async fn trash<'a, U>(url: U) -> io::Result<()>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use super::{DirEntry, DirEntrySync};
|
use super::DirEntry;
|
||||||
|
|
||||||
pub enum ReadDir {
|
pub enum ReadDir {
|
||||||
Local(super::local::ReadDir),
|
Local(super::local::ReadDir),
|
||||||
|
|
@ -13,18 +13,3 @@ impl ReadDir {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- ReadDirSync
|
|
||||||
pub enum ReadDirSync {
|
|
||||||
Local(super::local::ReadDirSync),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for ReadDirSync {
|
|
||||||
type Item = io::Result<DirEntrySync>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<io::Result<DirEntrySync>> {
|
|
||||||
match self {
|
|
||||||
Self::Local(local) => local.next().map(|result| result.map(Into::into)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,71 @@
|
||||||
use crate::provider::BufRead;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
pub enum RwFile {
|
pub enum RwFile {
|
||||||
Local(super::local::RwFile),
|
Local(super::local::RwFile),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RwFile {
|
impl AsyncRead for RwFile {
|
||||||
pub fn reader(self) -> Box<dyn BufRead> {
|
#[inline]
|
||||||
match self {
|
fn poll_read(
|
||||||
Self::Local(local) => Box::new(local.reader()),
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
buf: &mut tokio::io::ReadBuf<'_>,
|
||||||
|
) -> std::task::Poll<std::io::Result<()>> {
|
||||||
|
match &mut *self {
|
||||||
|
Self::Local(f) => Pin::new(f).poll_read(cx, buf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncWrite for RwFile {
|
||||||
|
#[inline]
|
||||||
|
fn poll_write(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
buf: &[u8],
|
||||||
|
) -> std::task::Poll<Result<usize, std::io::Error>> {
|
||||||
|
match &mut *self {
|
||||||
|
Self::Local(f) => Pin::new(f).poll_write(cx, buf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll_flush(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
) -> std::task::Poll<Result<(), std::io::Error>> {
|
||||||
|
match &mut *self {
|
||||||
|
Self::Local(f) => Pin::new(f).poll_flush(cx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll_shutdown(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
) -> std::task::Poll<Result<(), std::io::Error>> {
|
||||||
|
match &mut *self {
|
||||||
|
Self::Local(f) => Pin::new(f).poll_shutdown(cx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn poll_write_vectored(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut std::task::Context<'_>,
|
||||||
|
bufs: &[std::io::IoSlice<'_>],
|
||||||
|
) -> std::task::Poll<Result<usize, std::io::Error>> {
|
||||||
|
match &mut *self {
|
||||||
|
Self::Local(f) => Pin::new(f).poll_write_vectored(cx, bufs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_write_vectored(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Local(f) => f.is_write_vectored(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,13 +84,6 @@ impl Sftp {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_dir_sync<P>(path: P) -> io::Result<()>
|
|
||||||
where
|
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn read_link<P>(path: P) -> io::Result<PathBuf>
|
pub async fn read_link<P>(path: P) -> io::Result<PathBuf>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
|
|
@ -166,13 +159,6 @@ impl Sftp {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn symlink_metadata_sync<P>(path: P) -> io::Result<std::fs::Metadata>
|
|
||||||
where
|
|
||||||
P: AsRef<Path>,
|
|
||||||
{
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn trash<P>(path: P) -> io::Result<()>
|
pub async fn trash<P>(path: P) -> io::Result<()>
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ function M:peek(job)
|
||||||
for _, f in ipairs(files) do
|
for _, f in ipairs(files) do
|
||||||
local icon = File({
|
local icon = File({
|
||||||
url = Url(f.path),
|
url = Url(f.path),
|
||||||
cha = Cha { kind = f.attr:sub(1, 1) == "D" and 1 or 0 },
|
cha = Cha { mode = tonumber(f.attr:sub(1, 1) == "D" and "40700" or "100644", 8) },
|
||||||
}):icon()
|
}):icon()
|
||||||
|
|
||||||
if f.size > 0 then
|
if f.size > 0 then
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,20 @@
|
||||||
use mlua::{IntoLuaMulti, UserData, UserDataMethods, Value};
|
use mlua::{IntoLuaMulti, UserData, UserDataMethods, Value};
|
||||||
use yazi_binding::Error;
|
use yazi_binding::Error;
|
||||||
|
|
||||||
pub struct SizeCalculator(pub yazi_fs::SizeCalculator);
|
pub enum SizeCalculator {
|
||||||
|
Local(yazi_fs::provider::local::SizeCalculator),
|
||||||
|
Remote(yazi_fs::provider::SizeCalculator),
|
||||||
|
}
|
||||||
|
|
||||||
impl UserData for SizeCalculator {
|
impl UserData for SizeCalculator {
|
||||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||||
methods.add_async_method_mut("recv", |lua, mut me, ()| async move {
|
methods.add_async_method_mut("recv", |lua, mut me, ()| async move {
|
||||||
match me.0.next().await {
|
let next = match &mut *me {
|
||||||
|
Self::Local(it) => it.next().await,
|
||||||
|
Self::Remote(it) => it.next().await,
|
||||||
|
};
|
||||||
|
|
||||||
|
match next {
|
||||||
Ok(value) => value.into_lua_multi(&lua),
|
Ok(value) => value.into_lua_multi(&lua),
|
||||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
15
yazi-plugin/src/external/highlighter.rs
vendored
15
yazi-plugin/src/external/highlighter.rs
vendored
|
|
@ -3,9 +3,9 @@ use std::{borrow::Cow, io::Cursor, mem, path::{Path, PathBuf}, sync::OnceLock};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use ratatui::{layout::Size, text::{Line, Span, Text}};
|
use ratatui::{layout::Size, text::{Line, Span, Text}};
|
||||||
use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}};
|
use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}};
|
||||||
use tokio::io::AsyncBufReadExt;
|
use tokio::io::{AsyncBufReadExt, AsyncSeekExt, BufReader};
|
||||||
use yazi_config::{THEME, YAZI, preview::PreviewWrap};
|
use yazi_config::{THEME, YAZI, preview::PreviewWrap};
|
||||||
use yazi_fs::provider::local::Local;
|
use yazi_fs::provider::local::{self, Local};
|
||||||
use yazi_shared::{Ids, errors::PeekError, replace_to_printable};
|
use yazi_shared::{Ids, errors::PeekError, replace_to_printable};
|
||||||
|
|
||||||
static INCR: Ids = Ids::new();
|
static INCR: Ids = Ids::new();
|
||||||
|
|
@ -39,9 +39,9 @@ impl Highlighter {
|
||||||
pub fn abort() { INCR.next(); }
|
pub fn abort() { INCR.next(); }
|
||||||
|
|
||||||
pub async fn highlight(&self, skip: usize, size: Size) -> Result<Text<'static>, PeekError> {
|
pub async fn highlight(&self, skip: usize, size: Size) -> Result<Text<'static>, PeekError> {
|
||||||
let mut reader = Local::open(&self.path).await?.reader();
|
let mut reader = BufReader::new(Local::open(&self.path).await?);
|
||||||
|
|
||||||
let syntax = Self::find_syntax(&self.path).await;
|
let syntax = Self::find_syntax(&self.path, &mut reader).await;
|
||||||
let mut plain = syntax.is_err();
|
let mut plain = syntax.is_err();
|
||||||
|
|
||||||
let mut before = Vec::with_capacity(if plain { 0 } else { skip });
|
let mut before = Vec::with_capacity(if plain { 0 } else { skip });
|
||||||
|
|
@ -130,7 +130,10 @@ impl Highlighter {
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn find_syntax(path: &Path) -> Result<&'static SyntaxReference> {
|
async fn find_syntax(
|
||||||
|
path: &Path,
|
||||||
|
reader: &mut BufReader<local::RwFile>,
|
||||||
|
) -> Result<&'static SyntaxReference> {
|
||||||
let (_, syntaxes) = Self::init();
|
let (_, syntaxes) = Self::init();
|
||||||
let name = path.file_name().map(|n| n.to_string_lossy()).unwrap_or_default();
|
let name = path.file_name().map(|n| n.to_string_lossy()).unwrap_or_default();
|
||||||
if let Some(s) = syntaxes.find_syntax_by_extension(&name) {
|
if let Some(s) = syntaxes.find_syntax_by_extension(&name) {
|
||||||
|
|
@ -143,8 +146,8 @@ impl Highlighter {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
let mut reader = Local::open(&path).await?.reader();
|
|
||||||
reader.read_line(&mut line).await?;
|
reader.read_line(&mut line).await?;
|
||||||
|
reader.rewind().await?;
|
||||||
syntaxes.find_syntax_by_first_line(&line).ok_or_else(|| anyhow!("No syntax found"))
|
syntaxes.find_syntax_by_first_line(&line).ok_or_else(|| anyhow!("No syntax found"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -147,8 +147,14 @@ fn read_dir(lua: &Lua) -> mlua::Result<Function> {
|
||||||
|
|
||||||
fn calc_size(lua: &Lua) -> mlua::Result<Function> {
|
fn calc_size(lua: &Lua) -> mlua::Result<Function> {
|
||||||
lua.create_async_function(|lua, url: UrlRef| async move {
|
lua.create_async_function(|lua, url: UrlRef| async move {
|
||||||
match yazi_fs::SizeCalculator::new(&url).await {
|
let it = if let Some(path) = url.as_path() {
|
||||||
Ok(it) => SizeCalculator(it).into_lua_multi(&lua),
|
provider::local::SizeCalculator::new(path).await.map(SizeCalculator::Local)
|
||||||
|
} else {
|
||||||
|
provider::SizeCalculator::new(&*url).await.map(SizeCalculator::Remote)
|
||||||
|
};
|
||||||
|
|
||||||
|
match it {
|
||||||
|
Ok(it) => it.into_lua_multi(&lua),
|
||||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use tokio::sync::mpsc;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use yazi_config::Priority;
|
use yazi_config::Priority;
|
||||||
use yazi_fs::{FilesOp, SizeCalculator};
|
use yazi_fs::{FilesOp, provider};
|
||||||
use yazi_plugin::isolate;
|
use yazi_plugin::isolate;
|
||||||
use yazi_shared::{event::CmdCow, url::UrlBuf};
|
use yazi_shared::{event::CmdCow, url::UrlBuf};
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ impl Prework {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn size_do(&self, task: PreworkInSize) -> Result<(), PreworkOutSize> {
|
pub(crate) async fn size_do(&self, task: PreworkInSize) -> Result<(), PreworkOutSize> {
|
||||||
let length = SizeCalculator::total(&task.target).await.unwrap_or(0);
|
let length = provider::calculate(&task.target).await.unwrap_or(0);
|
||||||
task.throttle.done((task.target, length), |buf| {
|
task.throttle.done((task.target, length), |buf| {
|
||||||
{
|
{
|
||||||
let mut loading = self.sizing.write();
|
let mut loading = self.sizing.write();
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,13 @@ pub struct DirEntry<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DirEntry<'a> {
|
impl<'a> DirEntry<'a> {
|
||||||
|
#[must_use]
|
||||||
pub fn path(&self) -> PathBuf { self.dir.join(&self.name) }
|
pub fn path(&self) -> PathBuf { self.dir.join(&self.name) }
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn name(&self) -> Cow<'_, OsStr> { self.name.to_os_str() }
|
pub fn name(&self) -> Cow<'_, OsStr> { self.name.to_os_str() }
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn long_name(&self) -> Cow<'_, OsStr> { self.long_name.to_os_str() }
|
pub fn long_name(&self) -> Cow<'_, OsStr> { self.long_name.to_os_str() }
|
||||||
|
|
||||||
pub fn attrs(&self) -> &Attrs { &self.attrs }
|
pub fn attrs(&self) -> &Attrs { &self.attrs }
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue