refactor: simplify paths (#3297)

This commit is contained in:
三咲雅 misaki masa 2025-10-31 20:26:26 +08:00 committed by GitHub
parent b766cff69f
commit 604b86612a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 180 additions and 317 deletions

View file

@ -1,11 +1,11 @@
use std::{ffi::OsString, mem, path::MAIN_SEPARATOR_STR};
use std::{ffi::OsString, mem, path::{MAIN_SEPARATOR_STR, PathBuf}};
use anyhow::Result;
use yazi_fs::{CWD, path::expand_url, provider::{DirReader, FileHolder}};
use yazi_macro::{act, render, succ};
use yazi_parser::cmp::{CmpItem, ShowOpt, TriggerOpt};
use yazi_proxy::CmpProxy;
use yazi_shared::{OsStrSplit, data::Data, natsort, scheme::SchemeLike, url::{UrlBuf, UrlCow, UrnBuf}};
use yazi_shared::{OsStrSplit, data::Data, natsort, scheme::SchemeLike, url::{UrlBuf, UrlCow}};
use yazi_vfs::provider;
use crate::{Actor, Ctx};
@ -67,7 +67,7 @@ impl Actor for Trigger {
}
impl Trigger {
fn split_url(s: &str) -> Option<(UrlBuf, UrnBuf)> {
fn split_url(s: &str) -> Option<(UrlBuf, PathBuf)> {
let (scheme, path, ..) = UrlCow::parse(s.as_bytes()).ok()?;
if scheme.is_local() && path.as_os_str() == "~" {
@ -91,16 +91,16 @@ impl Trigger {
#[cfg(test)]
mod tests {
use yazi_shared::url::{UrlLike, Urn};
use yazi_shared::url::UrlLike;
use super::*;
fn compare(s: &str, parent: &str, child: &str) {
let (mut p, c) = Trigger::split_url(s).unwrap();
if let Some(u) = p.strip_prefix(yazi_fs::CWD.load().as_ref()) {
p = UrlBuf::from(&**u);
p = UrlBuf::from(u);
}
assert_eq!((p, c.as_urn()), (parent.parse().unwrap(), Urn::new(child)));
assert_eq!((p, c.to_str().unwrap()), (parent.parse().unwrap(), child));
}
#[cfg(unix)]

View file

@ -4,7 +4,7 @@ use mlua::{AnyUserData, ExternalError, FromLua, Lua, MetaMethod, UserData, UserD
use yazi_fs::{FsHash64, FsHash128};
use yazi_shared::{IntoOsStr, scheme::SchemeLike, url::{AsUrl, UrlCow, UrlLike}};
use crate::{Scheme, Urn, cached_field, deprecate};
use crate::{Scheme, cached_field, deprecate};
pub type UrlRef = UserDataRef<Url>;
@ -108,7 +108,10 @@ impl UserData for Url {
me.ext().map(|s| lua.create_string(s.as_encoded_bytes())).transpose()
});
cached_field!(fields, parent, |_, me| Ok(me.parent().map(Self::new)));
cached_field!(fields, urn, |_, me| Ok(Urn::new(me.urn())));
cached_field!(fields, urn, |_, me| {
// FIXME: remove type inference
Ok(super::Path::<std::path::PathBuf>::new(me.urn()))
});
cached_field!(fields, base, |_, me| Ok(me.base().map(Self::new)));
cached_field!(fields, scheme, |_, me| Ok(Scheme::new(&me.scheme)));

View file

@ -3,43 +3,34 @@ use std::{ops::Deref, path::PathBuf};
use mlua::{ExternalError, FromLua, Lua, UserData, Value};
use yazi_shared::path::PathBufLike;
pub struct Urn<P: PathBufLike = PathBuf> {
inner: yazi_shared::url::UrnBuf<P>,
}
pub struct Path<P: PathBufLike = PathBuf>(pub P);
impl<P> Deref for Urn<P>
impl<P> Deref for Path<P>
where
P: PathBufLike,
{
type Target = yazi_shared::url::UrnBuf<P>;
type Target = P;
fn deref(&self) -> &Self::Target { &self.inner }
fn deref(&self) -> &Self::Target { &self.0 }
}
impl<P> From<Urn<P>> for yazi_shared::url::UrnBuf<P>
impl<P> Path<P>
where
P: PathBufLike,
{
fn from(value: Urn<P>) -> Self { value.inner }
pub fn new(urn: impl Into<P>) -> Self { Self(urn.into()) }
}
impl<P> Urn<P>
where
P: PathBufLike,
{
pub fn new(urn: impl Into<yazi_shared::url::UrnBuf<P>>) -> Self { Self { inner: urn.into() } }
}
impl<P> FromLua for Urn<P>
impl<P> FromLua for Path<P>
where
P: PathBufLike,
{
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(match value {
Value::UserData(ud) => ud.take()?,
_ => Err("Expected a Urn".into_lua_err())?,
_ => Err("Expected a Path".into_lua_err())?,
})
}
}
impl<P> UserData for Urn<P> where P: PathBufLike {}
impl<P> UserData for Path<P> where P: PathBufLike {}

View file

@ -4,13 +4,13 @@ use futures::executor::block_on;
use hashbrown::HashSet;
use serde::Serialize;
use yazi_fs::{CWD, Xdg, path::expand_url};
use yazi_shared::url::{UrlBuf, UrlCow, UrlLike, UrnBuf};
use yazi_shared::url::{UrlBuf, UrlCow, UrlLike};
use yazi_vfs::provider;
#[derive(Debug, Default, Serialize)]
pub struct Boot {
pub cwds: Vec<UrlBuf>,
pub files: Vec<UrnBuf>,
pub files: Vec<PathBuf>,
pub local_events: HashSet<String>,
pub remote_events: HashSet<String>,
@ -22,25 +22,25 @@ pub struct Boot {
}
impl Boot {
async fn parse_entries(entries: &[UrlBuf]) -> (Vec<UrlBuf>, Vec<UrnBuf>) {
async fn parse_entries(entries: &[UrlBuf]) -> (Vec<UrlBuf>, Vec<PathBuf>) {
if entries.is_empty() {
return (vec![CWD.load().as_ref().clone()], vec![UrnBuf::default()]);
return (vec![CWD.load().as_ref().clone()], vec![PathBuf::default()]);
}
async fn go(entry: &UrlBuf) -> (UrlBuf, UrnBuf) {
async fn go(entry: &UrlBuf) -> (UrlBuf, PathBuf) {
let mut entry = expand_url(entry);
if let Ok(u @ UrlCow::Owned { .. }) = provider::absolute(&entry).await {
entry = u.into_owned();
}
let Some((parent, child)) = entry.pair() else {
return (entry, UrnBuf::default());
return (entry, PathBuf::default());
};
if provider::metadata(&entry).await.is_ok_and(|m| m.is_file()) {
(parent.into(), child.to_owned())
} else {
(entry, UrnBuf::default())
(entry, PathBuf::default())
}
}

View file

@ -1,13 +1,15 @@
use std::path::{Path, PathBuf};
use anyhow::Result;
use hashbrown::HashMap;
use yazi_fs::{Files, Filter, FilterCase};
use yazi_shared::url::{UrlBuf, Urn, UrnBuf};
use yazi_shared::url::UrlBuf;
use crate::tab::Folder;
pub struct Finder {
pub filter: Filter,
pub matched: HashMap<UrnBuf, u8>,
pub matched: HashMap<PathBuf, u8>,
lock: FinderLock,
}
@ -76,7 +78,7 @@ impl Finder {
}
impl Finder {
pub fn matched_idx(&self, folder: &Folder, urn: &Urn) -> Option<u8> {
pub fn matched_idx(&self, folder: &Folder, urn: &Path) -> Option<u8> {
if self.lock == *folder { self.matched.get(urn).copied() } else { None }
}
}

View file

@ -1,4 +1,4 @@
use std::mem;
use std::{mem, path::{Path, PathBuf}};
use yazi_config::{LAYOUT, YAZI};
use yazi_dds::Pubsub;
@ -6,7 +6,7 @@ use yazi_fs::{File, Files, FilesOp, FolderStage, cha::Cha};
use yazi_macro::err;
use yazi_parser::Step;
use yazi_proxy::MgrProxy;
use yazi_shared::{Id, url::{UrlBuf, Urn, UrnBuf}};
use yazi_shared::{Id, url::UrlBuf};
use yazi_widgets::Scrollable;
pub struct Folder {
@ -19,7 +19,7 @@ pub struct Folder {
pub cursor: usize,
pub page: usize,
pub trace: Option<UrnBuf>,
pub trace: Option<PathBuf>,
}
impl Default for Folder {
@ -108,7 +108,7 @@ impl Folder {
b
}
pub fn hover(&mut self, urn: &Urn) -> bool {
pub fn hover(&mut self, urn: &Path) -> bool {
if self.hovered().map(|h| h.urn()) == Some(urn) {
return self.arrow(0);
}
@ -117,7 +117,7 @@ impl Folder {
self.arrow(new - self.cursor as isize)
}
pub fn repos(&mut self, urn: Option<&Urn>) -> bool {
pub fn repos(&mut self, urn: Option<&Path>) -> bool {
if let Some(u) = urn {
self.hover(u)
} else if let Some(u) = &self.trace {

View file

@ -46,8 +46,8 @@ impl Sendable {
Some(t) if t == TypeId::of::<yazi_binding::Url>() => {
Data::Url(ud.take::<yazi_binding::Url>()?.into())
}
Some(t) if t == TypeId::of::<yazi_binding::Urn>() => {
Data::Urn(ud.take::<yazi_binding::Urn>()?.into())
Some(t) if t == TypeId::of::<yazi_binding::Path<std::path::PathBuf>>() => {
Data::Path(ud.take::<yazi_binding::Path<std::path::PathBuf>>()?.0)
}
Some(t) if t == TypeId::of::<yazi_binding::Id>() => {
Data::Id(**ud.borrow::<yazi_binding::Id>()?)
@ -83,7 +83,7 @@ impl Sendable {
Value::Table(tbl)
}
Data::Url(u) => yazi_binding::Url::new(u).into_lua(lua)?,
Data::Urn(u) => yazi_binding::Urn::new(u).into_lua(lua)?,
Data::Path(u) => yazi_binding::Path::<std::path::PathBuf>::new(u).into_lua(lua)?,
Data::Any(a) => {
if a.is::<yazi_fs::FilesOp>() {
lua.create_any_userdata(*a.downcast::<yazi_fs::FilesOp>().unwrap())?.into_lua(lua)?
@ -121,7 +121,7 @@ impl Sendable {
}
Data::Id(i) => yazi_binding::Id(*i).into_lua(lua)?,
Data::Url(u) => yazi_binding::Url::new(u.clone()).into_lua(lua)?,
Data::Urn(u) => yazi_binding::Urn::new(u.clone()).into_lua(lua)?,
Data::Path(u) => yazi_binding::Path::<std::path::PathBuf>::new(u).into_lua(lua)?,
Data::Bytes(b) => Value::String(lua.create_string(b)?),
Data::Any(a) => {
if let Some(t) = a.downcast_ref::<yazi_fs::FilesOp>() {
@ -214,8 +214,8 @@ impl Sendable {
Some(t) if t == TypeId::of::<yazi_binding::Url>() => {
DataKey::Url(ud.take::<yazi_binding::Url>()?.into())
}
Some(t) if t == TypeId::of::<yazi_binding::Urn>() => {
DataKey::Urn(ud.take::<yazi_binding::Urn>()?.into())
Some(t) if t == TypeId::of::<yazi_binding::Path>() => {
DataKey::Path(ud.take::<yazi_binding::Path>()?.0)
}
Some(t) if t == TypeId::of::<yazi_binding::Id>() => {
DataKey::Id(**ud.borrow::<yazi_binding::Id>()?)
@ -230,7 +230,7 @@ impl Sendable {
fn key_to_value(lua: &Lua, key: DataKey) -> mlua::Result<Value> {
match key {
DataKey::Url(u) => yazi_binding::Url::new(u).into_lua(lua),
DataKey::Urn(u) => yazi_binding::Urn::new(u).into_lua(lua),
DataKey::Path(u) => yazi_binding::Path::<std::path::PathBuf>::new(u).into_lua(lua),
_ => Self::key_to_value_ref(lua, &key),
}
}
@ -244,7 +244,7 @@ impl Sendable {
DataKey::String(s) => Value::String(lua.create_string(s.as_ref())?),
DataKey::Id(i) => yazi_binding::Id(*i).into_lua(lua)?,
DataKey::Url(u) => yazi_binding::Url::new(u.clone()).into_lua(lua)?,
DataKey::Urn(u) => yazi_binding::Urn::new(u.clone()).into_lua(lua)?,
DataKey::Path(u) => yazi_binding::Path::<std::path::PathBuf>::new(u).into_lua(lua)?,
DataKey::Bytes(b) => Value::String(lua.create_string(b)?),
})
}

View file

@ -59,6 +59,8 @@ impl Cha {
let mut kind = ChaKind::DUMMY;
let mode = r#type.map(ChaMode::from_bare).unwrap_or_default();
#[cfg(unix)]
use yazi_shared::path::PathLike;
#[cfg(unix)]
if _url.as_url().urn().is_hidden() {
kind |= ChaKind::HIDDEN;

View file

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

View file

@ -1,7 +1,7 @@
use std::{mem, ops::{Deref, DerefMut, Not}};
use std::{mem, ops::{Deref, DerefMut, Not}, path::{Path, PathBuf}};
use hashbrown::{HashMap, HashSet};
use yazi_shared::{Id, url::{Urn, UrnBuf}};
use yazi_shared::Id;
use super::{FilesSorter, Filter};
use crate::{FILES_TICKET, File, SortBy};
@ -14,7 +14,7 @@ pub struct Files {
version: u64,
pub revision: u64,
pub sizes: HashMap<UrnBuf, u64>,
pub sizes: HashMap<PathBuf, u64>,
sorter: FilesSorter,
filter: Option<Filter>,
@ -69,7 +69,7 @@ impl Files {
}
}
pub fn update_size(&mut self, mut sizes: HashMap<UrnBuf, u64>) {
pub fn update_size(&mut self, mut sizes: HashMap<PathBuf, u64>) {
if sizes.len() <= 50 {
sizes.retain(|k, v| self.sizes.get(k) != Some(v));
}
@ -120,19 +120,18 @@ impl Files {
}
#[cfg(unix)]
pub fn update_deleting(&mut self, urns: HashSet<UrnBuf>) -> Vec<usize> {
pub fn update_deleting(&mut self, urns: HashSet<PathBuf>) -> Vec<usize> {
use yazi_shared::path::PathLike;
if urns.is_empty() {
return vec![];
}
let (mut hidden, mut items) = if let Some(filter) = &self.filter {
urns
.into_iter()
.partition(|u| (!self.show_hidden && u.as_urn().is_hidden()) || !filter.matches(u.as_urn()))
urns.into_iter().partition(|u| (!self.show_hidden && u.is_hidden()) || !filter.matches(u))
} else if self.show_hidden {
(HashSet::new(), urns)
} else {
urns.into_iter().partition(|u| u.as_urn().is_hidden())
urns.into_iter().partition(|u| u.is_hidden())
};
let mut deleted = Vec::with_capacity(items.len());
@ -156,7 +155,7 @@ impl Files {
}
#[cfg(windows)]
pub fn update_deleting(&mut self, mut urns: HashSet<UrnBuf>) -> Vec<usize> {
pub fn update_deleting(&mut self, mut urns: HashSet<PathBuf>) -> Vec<usize> {
let mut deleted = Vec::with_capacity(urns.len());
if !urns.is_empty() {
let mut i = 0;
@ -179,8 +178,8 @@ impl Files {
pub fn update_updating(
&mut self,
files: HashMap<UrnBuf, File>,
) -> (HashMap<UrnBuf, File>, HashMap<UrnBuf, File>) {
files: HashMap<PathBuf, File>,
) -> (HashMap<PathBuf, File>, HashMap<PathBuf, File>) {
if files.is_empty() {
return Default::default();
}
@ -222,7 +221,7 @@ impl Files {
(hidden, items)
}
pub fn update_upserting(&mut self, files: HashMap<UrnBuf, File>) {
pub fn update_upserting(&mut self, files: HashMap<PathBuf, File>) {
if files.is_empty() {
return;
}
@ -271,7 +270,7 @@ impl Files {
impl Files {
// --- Items
#[inline]
pub fn position(&self, urn: &Urn) -> Option<usize> { self.iter().position(|f| urn == f.urn()) }
pub fn position(&self, urn: &Path) -> Option<usize> { self.iter().position(|f| urn == f.urn()) }
// --- Ticket
#[inline]

View file

@ -2,7 +2,7 @@ use std::{ffi::OsStr, fmt::Display, ops::Range};
use anyhow::Result;
use regex::bytes::{Regex, RegexBuilder};
use yazi_shared::{event::Cmd, url::Urn};
use yazi_shared::{event::Cmd, path::{AsPath, PathLike}};
pub struct Filter {
raw: String,
@ -24,7 +24,12 @@ impl Filter {
#[inline]
#[allow(private_bounds)]
pub fn matches(&self, name: impl Needle) -> bool { self.regex.is_match(name.needle()) }
pub fn matches<T>(&self, name: T) -> bool
where
T: AsPath,
{
self.regex.is_match(name.as_path().encoded_bytes())
}
#[inline]
pub fn highlighted(&self, name: impl AsRef<OsStr>) -> Option<Vec<Range<usize>>> {
@ -57,16 +62,3 @@ impl From<&Cmd> for FilterCase {
}
}
}
// --- Needle
trait Needle {
fn needle(&self) -> &[u8];
}
impl Needle for &OsStr {
fn needle(&self) -> &[u8] { self.as_encoded_bytes() }
}
impl Needle for &Urn {
fn needle(&self) -> &[u8] { self.encoded_bytes() }
}

View file

@ -1,8 +1,8 @@
use std::path::Path;
use std::path::{Path, PathBuf};
use hashbrown::{HashMap, HashSet};
use yazi_macro::relay;
use yazi_shared::{Id, Ids, url::{UrlBuf, UrlLike, UrnBuf}};
use yazi_shared::{Id, Ids, url::{UrlBuf, UrlLike}};
use super::File;
use crate::{cha::Cha, error::Error};
@ -14,13 +14,13 @@ pub enum FilesOp {
Full(UrlBuf, Vec<File>, Cha),
Part(UrlBuf, Vec<File>, Id),
Done(UrlBuf, Cha, Id),
Size(UrlBuf, HashMap<UrnBuf, u64>),
Size(UrlBuf, HashMap<PathBuf, u64>),
IOErr(UrlBuf, Error),
Creating(UrlBuf, Vec<File>),
Deleting(UrlBuf, HashSet<UrnBuf>),
Updating(UrlBuf, HashMap<UrnBuf, File>),
Upserting(UrlBuf, HashMap<UrnBuf, File>),
Deleting(UrlBuf, HashSet<PathBuf>),
Updating(UrlBuf, HashMap<PathBuf, File>),
Upserting(UrlBuf, HashMap<PathBuf, File>),
}
impl FilesOp {

View file

@ -4,8 +4,11 @@ use yazi_shared::{loc::LocBuf, url::{UrlBuf, UrlCow}};
pub fn clean_url<'a>(url: impl Into<UrlCow<'a>>) -> UrlBuf {
let cow: UrlCow = url.into();
let (path, uri, urn) =
clean_path_impl(&cow.loc(), cow.loc().base().count(), cow.loc().trail().count());
let (path, uri, urn) = clean_path_impl(
&cow.loc(),
cow.loc().base().components().count(),
cow.loc().trail().components().count(),
);
let loc = LocBuf::with(path, uri, urn).expect("Failed to create Loc from cleaned path");
UrlBuf { loc, scheme: cow.into_scheme().into() }

View file

@ -19,8 +19,8 @@ fn expand_url_impl<'a>(url: Url<'a>) -> UrlCow<'a> {
let rest_diff = n_rest.components().count() as isize - o_rest.components().count() as isize;
let urn_diff = n_urn.components().count() as isize - o_urn.components().count() as isize;
let uri_count = url.uri().count() as isize;
let urn_count = url.urn().count() as isize;
let uri_count = url.uri().components().count() as isize;
let urn_count = url.urn().components().count() as isize;
let loc = LocBuf::with(
PathBuf::from_iter([n_base, n_rest, n_urn]),
@ -83,15 +83,19 @@ pub fn absolute_url<'a>(url: Url<'a>) -> UrlCow<'a> {
let add = home.components().count() - 1; // Home root ("~") has offset by the absolute root ("/")
let loc = LocBuf::with(
home.join(rest),
url.uri().count() + if url.has_base() { 0 } else { add },
url.urn().count() + if url.has_trail() { 0 } else { add },
url.uri().components().count() + if url.has_base() { 0 } else { add },
url.urn().components().count() + if url.has_trail() { 0 } else { add },
)
.expect("Failed to create Loc from home directory");
UrlBuf { loc, scheme: url.scheme.into() }.into()
} else if !url.is_absolute() {
let cwd = CWD.path();
let loc = LocBuf::with(cwd.join(url.loc), url.uri().count(), url.urn().count())
.expect("Failed to create Loc from relative path");
let loc = LocBuf::with(
cwd.join(url.loc),
url.uri().components().count(),
url.urn().components().count(),
)
.expect("Failed to create Loc from relative path");
UrlBuf { loc, scheme: url.scheme.into() }.into()
} else {
url.into()

View file

@ -1,7 +1,7 @@
use std::cmp::Ordering;
use std::{cmp::Ordering, path::PathBuf};
use hashbrown::HashMap;
use yazi_shared::{LcgRng, natsort, translit::Transliterator, url::{UrlLike, UrnBuf}};
use yazi_shared::{LcgRng, natsort, path::PathLike, translit::Transliterator, url::UrlLike};
use crate::{File, SortBy};
@ -15,7 +15,7 @@ pub struct FilesSorter {
}
impl FilesSorter {
pub(super) fn sort(&self, items: &mut [File], sizes: &HashMap<UrnBuf, u64>) {
pub(super) fn sort(&self, items: &mut [File], sizes: &HashMap<PathBuf, u64>) {
if items.is_empty() {
return;
}

View file

@ -1,14 +1,14 @@
use std::{ffi::OsString, path::MAIN_SEPARATOR_STR};
use std::{ffi::OsString, path::{MAIN_SEPARATOR_STR, PathBuf}};
use anyhow::bail;
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_shared::{Id, event::CmdCow, url::{UrlBuf, UrnBuf}};
use yazi_shared::{Id, event::CmdCow, url::UrlBuf};
#[derive(Debug, Default)]
pub struct ShowOpt {
pub cache: Vec<CmpItem>,
pub cache_name: UrlBuf,
pub word: UrnBuf,
pub word: PathBuf,
pub ticket: Id,
}

View file

@ -1,13 +1,14 @@
use std::path::PathBuf;
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_shared::url::UrnBuf;
#[derive(Debug, Default)]
pub struct HoverOpt {
pub urn: Option<UrnBuf>,
pub urn: Option<PathBuf>,
}
impl From<Option<UrnBuf>> for HoverOpt {
fn from(urn: Option<UrnBuf>) -> Self { Self { urn } }
impl From<Option<PathBuf>> for HoverOpt {
fn from(urn: Option<PathBuf>) -> Self { Self { urn } }
}
impl FromLua for HoverOpt {

View file

@ -1,5 +1,5 @@
use mlua::{IntoLua, Lua, Table};
use yazi_binding::{Cha, File, Id, Url, Urn};
use yazi_binding::{Cha, File, Id, Path, Url};
pub(super) struct FilesOp(yazi_fs::FilesOp);
@ -34,8 +34,8 @@ impl FilesOp {
Ok(Self(yazi_fs::FilesOp::Size(
url.into(),
sizes
.pairs::<Urn, u64>()
.map(|r| r.map(|(urn, size)| (urn.into(), size)))
.pairs::<Path, u64>()
.map(|r| r.map(|(urn, size)| (urn.0, size)))
.collect::<mlua::Result<_>>()?,
)))
}

View file

@ -1,10 +1,10 @@
use std::{any::Any, borrow::Cow};
use std::{any::Any, borrow::Cow, path::PathBuf};
use anyhow::{Result, bail};
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use crate::{Id, SStr, data::DataKey, url::{UrlBuf, UrlCow, UrnBuf}};
use crate::{Id, SStr, data::DataKey, url::{UrlBuf, UrlCow}};
// --- Data
#[derive(Debug, Deserialize, Serialize)]
@ -21,7 +21,7 @@ pub enum Data {
#[serde(skip_deserializing)]
Url(UrlBuf),
#[serde(skip_deserializing)]
Urn(UrnBuf),
Path(PathBuf),
#[serde(skip)]
Bytes(Vec<u8>),
#[serde(skip)]

View file

@ -1,9 +1,9 @@
use std::borrow::Cow;
use std::{borrow::Cow, path::PathBuf};
use ordered_float::OrderedFloat;
use serde::{Deserialize, Serialize, de};
use crate::{Id, SStr, url::{UrlBuf, UrlCow, UrnBuf}};
use crate::{Id, SStr, url::{UrlBuf, UrlCow}};
#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(untagged)]
@ -18,7 +18,7 @@ pub enum DataKey {
#[serde(skip_deserializing)]
Url(UrlBuf),
#[serde(skip_deserializing)]
Urn(UrnBuf),
Path(PathBuf),
#[serde(skip)]
Bytes(Vec<u8>),
}

View file

@ -2,7 +2,7 @@ use std::{cmp, ffi::OsStr, fmt::{self, Debug, Formatter}, hash::{Hash, Hasher},
use anyhow::Result;
use crate::{loc::Loc, path::{PathBufLike, PathLike}, url::{Uri, Urn}};
use crate::{loc::Loc, path::{PathBufLike, PathLike}};
#[derive(Clone, Default, Eq)]
pub struct LocBuf<P: PathBufLike = PathBuf> {
@ -215,19 +215,19 @@ where
P: PathBufLike,
{
#[inline]
pub fn uri(&self) -> &Uri<P::Borrowed> { self.as_loc().uri() }
pub fn uri(&self) -> &P::Borrowed { self.as_loc().uri() }
#[inline]
pub fn urn(&self) -> &Urn<P::Borrowed> { self.as_loc().urn() }
pub fn urn(&self) -> &P::Borrowed { self.as_loc().urn() }
#[inline]
pub fn base(&self) -> &Urn<P::Borrowed> { self.as_loc().base() }
pub fn base(&self) -> &P::Borrowed { self.as_loc().base() }
#[inline]
pub fn has_base(&self) -> bool { self.as_loc().has_base() }
#[inline]
pub fn trail(&self) -> &Urn<P::Borrowed> { self.as_loc().trail() }
pub fn trail(&self) -> &P::Borrowed { self.as_loc().trail() }
#[inline]
pub fn has_trail(&self) -> bool { self.as_loc().has_trail() }

View file

@ -2,7 +2,7 @@ use std::{hash::{Hash, Hasher}, ops::Deref, path::Path};
use anyhow::{Result, bail};
use crate::{loc::LocBuf, path::{PathInner, PathLike}, url::{Uri, Urn}};
use crate::{loc::LocBuf, path::{PathInner, PathLike}};
#[derive(Debug)]
pub struct Loc<'a, P: ?Sized + PathLike = Path> {
@ -169,34 +169,34 @@ where
pub fn as_path(self) -> &'a P { self.inner }
#[inline]
pub fn uri(self) -> &'a Uri<P> {
Uri::new(unsafe {
pub fn uri(self) -> &'a P {
unsafe {
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(self.inner.len() - self.uri..))
})
}
}
#[inline]
pub fn urn(self) -> &'a Urn<P> {
Urn::new(unsafe {
pub fn urn(self) -> &'a P {
unsafe {
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(self.inner.len() - self.urn..))
})
}
}
#[inline]
pub fn base(self) -> &'a Urn<P> {
Urn::new(unsafe {
pub fn base(self) -> &'a P {
unsafe {
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(..self.inner.len() - self.uri))
})
}
}
#[inline]
pub fn has_base(self) -> bool { self.inner.len() != self.uri }
#[inline]
pub fn trail(self) -> &'a Urn<P> {
Urn::new(unsafe {
pub fn trail(self) -> &'a P {
unsafe {
P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(..self.inner.len() - self.urn))
})
}
}
#[inline]

View file

@ -1,5 +1,9 @@
use std::{ffi::{OsStr, OsString}, path::{Path, PathBuf}};
pub trait AsPath {
fn as_path(&self) -> &(impl ?Sized + PathLike);
}
pub trait PathLike: AsRef<Self> {
type Inner: ?Sized + PathInner;
type Owned: PathBufLike + Into<Self::Owned>;
@ -21,6 +25,11 @@ pub trait PathLike: AsRef<Self> {
unsafe fn from_encoded_bytes(bytes: &[u8]) -> &Self;
#[cfg(unix)]
fn is_hidden(&self) -> bool {
self.file_name().map_or(false, |n| n.encoded_bytes().get(0) == Some(&b'.'))
}
fn join<T>(&self, base: T) -> Self::Owned
where
T: AsRef<Self>;
@ -58,6 +67,22 @@ pub trait PathInner {
fn encoded_bytes(&self) -> &[u8];
}
impl AsPath for &OsStr {
fn as_path(&self) -> &(impl ?Sized + PathLike) { Path::new(self) }
}
impl AsPath for &Path {
fn as_path(&self) -> &(impl ?Sized + PathLike) { *self }
}
impl AsPath for PathBuf {
fn as_path(&self) -> &(impl ?Sized + PathLike) { self.as_path() }
}
impl AsPath for &PathBuf {
fn as_path(&self) -> &(impl ?Sized + PathLike) { (*self).as_path() }
}
impl PathLike for Path {
type Components<'a> = std::path::Components<'a>;
type Inner = OsStr;

View file

@ -146,7 +146,7 @@ impl UrlBuf {
pub fn is_internal(&self) -> bool {
match self.scheme {
Scheme::Regular | Scheme::Sftp(_) => true,
Scheme::Search(_) => !self.loc.uri().is_empty(),
Scheme::Search(_) => !self.loc.uri().as_os_str().is_empty(),
Scheme::Archive(_) => false,
}
}

View file

@ -25,8 +25,8 @@ impl<'a> Encode<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
macro_rules! w {
($default_uri:expr, $default_urn:expr) => {{
let uri = self.0.0.loc.uri().count();
let urn = self.0.0.loc.urn().count();
let uri = self.0.0.loc.uri().components().count();
let urn = self.0.0.loc.urn().components().count();
match (uri != $default_uri, urn != $default_urn) {
(true, true) => write!(f, ":{uri}:{urn}"),
(true, false) => write!(f, ":{uri}"),

View file

@ -1 +1 @@
yazi_macro::mod_flat!(buf component cov cow display encode traits uri url urn);
yazi_macro::mod_flat!(buf component cov cow display encode traits url);

View file

@ -1,6 +1,6 @@
use std::{borrow::Cow, ffi::OsStr, path::{Path, PathBuf}};
use crate::{scheme::{AsScheme, SchemeRef}, url::{Components, Display, Uri, Url, UrlBuf, UrlCow, Urn}};
use crate::{scheme::{AsScheme, SchemeRef}, url::{Components, Display, Url, UrlBuf, UrlCow}};
// --- AsUrl
pub trait AsUrl {
@ -107,7 +107,7 @@ where
fn os_str(&self) -> Cow<'_, OsStr> { self.components().os_str() }
fn pair(&self) -> Option<(Url<'_>, &Urn)> { self.as_url().pair() }
fn pair(&self) -> Option<(Url<'_>, &Path)> { self.as_url().pair() }
fn parent(&self) -> Option<Url<'_>> { self.as_url().parent() }
@ -115,11 +115,11 @@ where
fn stem(&self) -> Option<&OsStr> { self.as_url().stem() }
fn strip_prefix(&self, base: impl AsUrl) -> Option<&Urn> { self.as_url().strip_prefix(base) }
fn strip_prefix(&self, base: impl AsUrl) -> Option<&Path> { self.as_url().strip_prefix(base) }
fn uri(&self) -> &Uri { self.as_url().uri() }
fn uri(&self) -> &Path { self.as_url().uri() }
fn urn(&self) -> &Urn { self.as_url().urn() }
fn urn(&self) -> &Path { self.as_url().urn() }
}
impl UrlLike for UrlBuf {}

View file

@ -1,39 +0,0 @@
use std::{ops::Deref, path::Path};
use crate::path::PathLike;
#[derive(Debug, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct Uri<P: ?Sized + PathLike = Path>(P);
impl<P> Uri<P>
where
P: ?Sized + PathLike,
{
#[inline]
pub fn new<T: AsRef<P> + ?Sized>(p: &T) -> &Self {
unsafe { &*(p.as_ref() as *const P as *const Self) }
}
#[inline]
pub fn count(&self) -> usize { self.0.components().count() }
#[inline]
pub fn is_empty(&self) -> bool { self.0.len() == 0 }
}
impl<P> Deref for Uri<P>
where
P: ?Sized + PathLike,
{
type Target = P;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl<P> AsRef<P> for Uri<P>
where
P: ?Sized + PathLike,
{
fn as_ref(&self) -> &P { &self.0 }
}

View file

@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::Path};
use hashbrown::Equivalent;
use crate::{loc::{Loc, LocBuf}, scheme::SchemeRef, url::{AsUrl, Components, Encode, Uri, UrlBuf, Urn}};
use crate::{loc::{Loc, LocBuf}, scheme::SchemeRef, url::{AsUrl, Components, Encode, UrlBuf}};
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct Url<'a> {
@ -79,13 +79,13 @@ impl<'a> Url<'a> {
UrlBuf { loc, scheme: self.scheme.into() }
}
pub fn strip_prefix(self, base: impl AsUrl) -> Option<&'a Urn> {
pub fn strip_prefix(self, base: impl AsUrl) -> Option<&'a Path> {
use SchemeRef as S;
let base = base.as_url();
let prefix = self.loc.strip_prefix(base.loc)?;
Some(Urn::new(match (self.scheme, base.scheme) {
Some(match (self.scheme, base.scheme) {
// Same scheme
(S::Regular, S::Regular) => Some(prefix),
(S::Search(_), S::Search(_)) => Some(prefix),
@ -97,10 +97,10 @@ impl<'a> Url<'a> {
(S::Search(_), S::Regular) => Some(prefix),
// Only the entry of archives is a local file
(S::Regular, S::Archive(_)) => Some(prefix).filter(|_| base.uri().is_empty()),
(S::Search(_), S::Archive(_)) => Some(prefix).filter(|_| base.uri().is_empty()),
(S::Archive(_), S::Regular) => Some(prefix).filter(|_| self.uri().is_empty()),
(S::Archive(_), S::Search(_)) => Some(prefix).filter(|_| self.uri().is_empty()),
(S::Regular, S::Archive(_)) => Some(prefix).filter(|_| base.uri().as_os_str().is_empty()),
(S::Search(_), S::Archive(_)) => Some(prefix).filter(|_| base.uri().as_os_str().is_empty()),
(S::Archive(_), S::Regular) => Some(prefix).filter(|_| self.uri().as_os_str().is_empty()),
(S::Archive(_), S::Search(_)) => Some(prefix).filter(|_| self.uri().as_os_str().is_empty()),
// Independent virtual file space
(S::Regular, S::Sftp(_)) => None,
@ -109,14 +109,14 @@ impl<'a> Url<'a> {
(S::Sftp(_), S::Regular) => None,
(S::Sftp(_), S::Search(_)) => None,
(S::Sftp(_), S::Archive(_)) => None,
}?))
}?)
}
#[inline]
pub fn uri(self) -> &'a Uri { self.loc.uri() }
pub fn uri(self) -> &'a Path { self.loc.uri() }
#[inline]
pub fn urn(self) -> &'a Urn { self.loc.urn() }
pub fn urn(self) -> &'a Path { self.loc.urn() }
#[inline]
pub fn name(self) -> Option<&'a OsStr> { self.loc.name() }
@ -154,13 +154,17 @@ impl<'a> Url<'a> {
S::Regular => Self { loc: parent.into(), scheme: S::Regular },
// Search
S::Search(_) if uri.is_empty() => Self { loc: parent.into(), scheme: S::Regular },
S::Search(_) if uri.as_os_str().is_empty() => {
Self { loc: parent.into(), scheme: S::Regular }
}
S::Search(_) => {
Self { loc: Loc::new(parent, self.loc.base(), self.loc.base()), scheme: self.scheme }
}
// Archive
S::Archive(_) if uri.is_empty() => Self { loc: parent.into(), scheme: S::Regular },
S::Archive(_) if uri.as_os_str().is_empty() => {
Self { loc: parent.into(), scheme: S::Regular }
}
S::Archive(_) if uri.components().nth(1).is_none() => {
Self { loc: Loc::zeroed(parent), scheme: self.scheme }
}
@ -196,7 +200,7 @@ impl<'a> Url<'a> {
}
#[inline]
pub fn pair(self) -> Option<(Self, &'a Urn)> { Some((self.parent()?, self.loc.urn())) }
pub fn pair(self) -> Option<(Self, &'a Path)> { Some((self.parent()?, self.loc.urn())) }
#[inline]
pub fn as_path(self) -> Option<&'a Path> {

View file

@ -1,124 +0,0 @@
use std::{borrow::Borrow, ops::Deref, path::{Path, PathBuf}};
use serde::Serialize;
use crate::path::{PathBufLike, PathLike};
#[derive(Debug, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct Urn<P: ?Sized + PathLike = Path>(P);
impl<P> Urn<P>
where
P: ?Sized + PathLike,
{
#[inline]
pub fn new<T: AsRef<P> + ?Sized>(p: &T) -> &Self {
unsafe { &*(p.as_ref() as *const P as *const Self) }
}
#[inline]
pub fn name(&self) -> Option<&P::Inner> { self.0.file_name() }
#[inline]
pub fn count(&self) -> usize { self.0.components().count() }
#[inline]
pub fn encoded_bytes(&self) -> &[u8] { self.0.encoded_bytes() }
#[cfg(unix)]
#[inline]
pub fn is_hidden(&self) -> bool {
use crate::path::PathInner;
self.name().is_some_and(|s| s.encoded_bytes().starts_with(b"."))
}
}
impl<P> Deref for Urn<P>
where
P: ?Sized + PathLike,
{
type Target = P;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl<P> AsRef<P> for Urn<P>
where
P: ?Sized + PathLike,
{
fn as_ref(&self) -> &P { &self.0 }
}
impl<P> From<&Urn<P>> for PathBuf
where
P: ?Sized + PathLike + ToOwned<Owned = PathBuf>,
{
fn from(value: &Urn<P>) -> Self { value.0.to_owned() }
}
impl<P> ToOwned for Urn<P>
where
P: ?Sized + PathLike + ToOwned<Owned = <P as PathLike>::Owned>,
UrnBuf<<P as PathLike>::Owned>: Borrow<Urn<P>>,
{
type Owned = UrnBuf<<P as PathLike>::Owned>;
fn to_owned(&self) -> Self::Owned { UrnBuf(self.0.to_owned()) }
}
impl<P> PartialEq<UrnBuf<P::Owned>> for &Urn<P>
where
P: ?Sized + PathLike + PartialEq<P::Owned>,
{
fn eq(&self, other: &UrnBuf<P::Owned>) -> bool { self.0 == other.0 }
}
// --- UrnBuf
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize)]
pub struct UrnBuf<P: PathBufLike = PathBuf>(P);
impl<P> Borrow<Urn<P::Borrowed>> for UrnBuf<P>
where
P: PathBufLike,
{
fn borrow(&self) -> &Urn<P::Borrowed> { Urn::new(&self.0) }
}
impl<P> Deref for UrnBuf<P>
where
P: PathBufLike,
{
type Target = Urn<P::Borrowed>;
fn deref(&self) -> &Self::Target { Urn::new(&self.0) }
}
impl<P> AsRef<P::Borrowed> for UrnBuf<P>
where
P: PathBufLike,
{
fn as_ref(&self) -> &P::Borrowed { Urn::new(&self.0) }
}
impl<P> PartialEq<Urn<P::Borrowed>> for UrnBuf<P>
where
P: PathBufLike + PartialEq<P::Borrowed>,
{
fn eq(&self, other: &Urn<P::Borrowed>) -> bool { self.0 == other.0 }
}
impl<T> From<T> for UrnBuf<PathBuf>
where
T: Into<PathBuf>,
{
fn from(value: T) -> Self { Self(value.into()) }
}
impl<P> UrnBuf<P>
where
P: PathBufLike,
{
#[inline]
pub fn as_urn(&self) -> &Urn<P::Borrowed> { self }
}