diff --git a/yazi-actor/src/lives/file.rs b/yazi-actor/src/lives/file.rs index 69f3052d..aeca4b56 100644 --- a/yazi-actor/src/lives/file.rs +++ b/yazi-actor/src/lives/file.rs @@ -77,7 +77,7 @@ impl UserData for File { yazi_binding::impl_file_methods!(methods); methods.add_method("size", |_, me, ()| { - Ok(if me.is_dir() { me.folder.files.sizes.get(me.urn()).copied() } else { Some(me.len) }) + Ok(if me.is_dir() { me.folder.files.sizes.get(&me.urn()).copied() } else { Some(me.len) }) }); methods.add_method("mime", |lua, me, ()| { lua.named_registry_value::("cx")?.borrow_scoped(|core: &yazi_core::Core| { diff --git a/yazi-actor/src/mgr/cd.rs b/yazi-actor/src/mgr/cd.rs index 6b85e955..3ed6b1ec 100644 --- a/yazi-actor/src/mgr/cd.rs +++ b/yazi-actor/src/mgr/cd.rs @@ -9,7 +9,7 @@ use yazi_fs::{File, FilesOp, path::expand_url}; use yazi_macro::{act, err, render, succ}; use yazi_parser::mgr::CdOpt; use yazi_proxy::{CmpProxy, InputProxy, MgrProxy}; -use yazi_shared::{Debounce, data::Data, errors::InputError, url::{AsUrl, UrlBuf, UrlLike}}; +use yazi_shared::{Debounce, data::Data, errors::InputError, path::PathLike, url::{AsUrl, UrlBuf, UrlLike}}; use yazi_vfs::VfsFile; use crate::{Actor, Ctx}; @@ -85,7 +85,7 @@ impl Cd { } if let Some(p) = url.parent() { - FilesOp::Upserting(p.into(), [(url.urn().to_owned(), file)].into()).emit(); + FilesOp::Upserting(p.into(), [(url.urn().owned(), file)].into()).emit(); } MgrProxy::reveal(&url); } diff --git a/yazi-actor/src/mgr/create.rs b/yazi-actor/src/mgr/create.rs index 978860fd..0b73d6c9 100644 --- a/yazi-actor/src/mgr/create.rs +++ b/yazi-actor/src/mgr/create.rs @@ -4,7 +4,7 @@ use yazi_fs::{File, FilesOp}; use yazi_macro::{ok_or_not_found, succ}; use yazi_parser::mgr::CreateOpt; use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy}; -use yazi_shared::{data::Data, url::{UrlBuf, UrlLike}}; +use yazi_shared::{data::Data, path::PathLike, url::{UrlBuf, UrlLike}}; use yazi_vfs::{VfsFile, maybe_exists, provider}; use yazi_watcher::WATCHER; @@ -51,7 +51,7 @@ impl Create { && let Some((parent, urn)) = real.pair() { ok_or_not_found!(provider::remove_file(&new).await); - FilesOp::Deleting(parent.into(), [urn.to_owned()].into()).emit(); + FilesOp::Deleting(parent.into(), [urn.owned()].into()).emit(); provider::create(&new).await?; } else if let Some(parent) = new.parent() { provider::create_dir_all(parent).await.ok(); @@ -65,7 +65,7 @@ impl Create { && let Some((parent, urn)) = real.pair() { let file = File::new(&real).await?; - FilesOp::Upserting(parent.into(), [(urn.to_owned(), file)].into()).emit(); + FilesOp::Upserting(parent.into(), [(urn.owned(), file)].into()).emit(); MgrProxy::reveal(&real); } diff --git a/yazi-actor/src/mgr/filter_do.rs b/yazi-actor/src/mgr/filter_do.rs index d5de8094..6998907b 100644 --- a/yazi-actor/src/mgr/filter_do.rs +++ b/yazi-actor/src/mgr/filter_do.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_fs::Filter; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::FilterOpt; -use yazi_shared::data::Data; +use yazi_shared::{data::Data, path::PathLike}; use crate::{Actor, Ctx}; @@ -16,10 +16,10 @@ impl Actor for FilterDo { fn act(cx: &mut Ctx, opt: Self::Options) -> Result { let filter = if opt.query.is_empty() { None } else { Some(Filter::new(&opt.query, opt.case)?) }; - let hovered = cx.hovered().map(|f| f.urn().to_owned()); + let hovered = cx.hovered().map(|f| f.urn().owned()); cx.current_mut().files.set_filter(filter); - if cx.hovered().map(|f| f.urn()) != hovered.as_deref() { + if cx.hovered().map(|f| f.urn()) != hovered.as_ref().map(Into::into) { act!(mgr:hover, cx, hovered)?; act!(mgr:peek, cx)?; act!(mgr:watch, cx)?; diff --git a/yazi-actor/src/mgr/hidden.rs b/yazi-actor/src/mgr/hidden.rs index efc55f03..2aba7f2b 100644 --- a/yazi-actor/src/mgr/hidden.rs +++ b/yazi-actor/src/mgr/hidden.rs @@ -3,7 +3,7 @@ use yazi_core::tab::Folder; use yazi_fs::FolderStage; use yazi_macro::{act, render, render_and, succ}; use yazi_parser::mgr::HiddenOpt; -use yazi_shared::data::Data; +use yazi_shared::{data::Data, path::PathLike}; use crate::{Actor, Ctx}; @@ -18,7 +18,7 @@ impl Actor for Hidden { let state = opt.state.bool(cx.tab().pref.show_hidden); cx.tab_mut().pref.show_hidden = state; - let hovered = cx.hovered().map(|f| f.urn().to_owned()); + let hovered = cx.hovered().map(|f| f.urn().owned()); let apply = |f: &mut Folder| { if f.stage == FolderStage::Loading { render!(); @@ -43,7 +43,7 @@ impl Actor for Hidden { { render!(h.repos(None)); act!(mgr:peek, cx, true)?; - } else if hovered.as_deref() != cx.hovered().map(|f| f.urn()) { + } else if cx.hovered().map(|f| f.urn()) != hovered.as_ref().map(Into::into) { act!(mgr:peek, cx)?; act!(mgr:watch, cx)?; } diff --git a/yazi-actor/src/mgr/hover.rs b/yazi-actor/src/mgr/hover.rs index 9007d4ba..75e8afdb 100644 --- a/yazi-actor/src/mgr/hover.rs +++ b/yazi-actor/src/mgr/hover.rs @@ -22,7 +22,7 @@ impl Actor for Hover { } // Repos CWD - tab.current.repos(opt.urn.as_deref()); + tab.current.repos(opt.urn.as_ref().map(Into::into)); // Turn on tracing if let (Some(h), Some(u)) = (tab.hovered(), opt.urn) diff --git a/yazi-actor/src/mgr/rename.rs b/yazi-actor/src/mgr/rename.rs index 02c0d166..068f7e47 100644 --- a/yazi-actor/src/mgr/rename.rs +++ b/yazi-actor/src/mgr/rename.rs @@ -5,7 +5,7 @@ use yazi_fs::{File, FilesOp}; use yazi_macro::{act, err, ok_or_not_found, succ}; use yazi_parser::mgr::RenameOpt; use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy}; -use yazi_shared::{Id, data::Data, url::{UrlBuf, UrlLike}}; +use yazi_shared::{Id, data::Data, path::PathLike, url::{UrlBuf, UrlLike}}; use yazi_vfs::{VfsFile, maybe_exists, provider}; use yazi_watcher::WATCHER; @@ -73,7 +73,7 @@ impl Rename { && let Some((parent, urn)) = u.pair() { ok_or_not_found!(provider::rename(&u, &new).await); - FilesOp::Deleting(parent.to_owned(), [urn.to_owned()].into()).emit(); + FilesOp::Deleting(parent.to_owned(), [urn.owned()].into()).emit(); } let new = provider::casefold(&new).await?; @@ -81,10 +81,10 @@ impl Rename { let file = File::new(&new).await?; if new_p == old_p { - FilesOp::Upserting(old_p.into(), [(old_n.to_owned(), file)].into()).emit(); + FilesOp::Upserting(old_p.into(), [(old_n.owned(), file)].into()).emit(); } else { - FilesOp::Deleting(old_p.into(), [old_n.to_owned()].into()).emit(); - FilesOp::Upserting(new_p.into(), [(new_n.to_owned(), file)].into()).emit(); + FilesOp::Deleting(old_p.into(), [old_n.owned()].into()).emit(); + FilesOp::Upserting(new_p.into(), [(new_n.owned(), file)].into()).emit(); } MgrProxy::reveal(&new); diff --git a/yazi-actor/src/mgr/reveal.rs b/yazi-actor/src/mgr/reveal.rs index f8f874aa..d174d10f 100644 --- a/yazi-actor/src/mgr/reveal.rs +++ b/yazi-actor/src/mgr/reveal.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_fs::{File, FilesOp}; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::RevealOpt; -use yazi_shared::{data::Data, url::UrlLike}; +use yazi_shared::{data::Data, path::PathLike, url::UrlLike}; use crate::{Actor, Ctx}; @@ -31,7 +31,7 @@ impl Actor for Reveal { } // Now, we can safely hover on the target - act!(mgr:hover, cx, Some(child.to_owned()))?; + act!(mgr:hover, cx, Some(child.owned()))?; act!(mgr:peek, cx)?; act!(mgr:watch, cx)?; diff --git a/yazi-actor/src/mgr/sort.rs b/yazi-actor/src/mgr/sort.rs index f0348b01..d29a2efd 100644 --- a/yazi-actor/src/mgr/sort.rs +++ b/yazi-actor/src/mgr/sort.rs @@ -3,7 +3,7 @@ use yazi_core::tab::Folder; use yazi_fs::{FilesSorter, FolderStage}; use yazi_macro::{act, render, render_and, succ}; use yazi_parser::mgr::SortOpt; -use yazi_shared::data::Data; +use yazi_shared::{data::Data, path::PathLike}; use crate::{Actor, Ctx}; @@ -23,7 +23,7 @@ impl Actor for Sort { pref.sort_translit = opt.translit.unwrap_or(pref.sort_translit); let sorter = FilesSorter::from(&*pref); - let hovered = cx.hovered().map(|f| f.urn().to_owned()); + let hovered = cx.hovered().map(|f| f.urn().owned()); let apply = |f: &mut Folder| { if f.stage == FolderStage::Loading { render!(); @@ -49,7 +49,7 @@ impl Actor for Sort { { render!(h.repos(None)); act!(mgr:peek, cx, true)?; - } else if hovered.as_deref() != cx.hovered().map(|f| f.urn()) { + } else if cx.hovered().map(|f| f.urn()) != hovered.as_ref().map(Into::into) { act!(mgr:peek, cx)?; act!(mgr:watch, cx)?; } diff --git a/yazi-actor/src/mgr/update_files.rs b/yazi-actor/src/mgr/update_files.rs index 4fe19653..b785e38a 100644 --- a/yazi-actor/src/mgr/update_files.rs +++ b/yazi-actor/src/mgr/update_files.rs @@ -57,7 +57,7 @@ impl UpdateFiles { let tab = cx.tab_mut(); let urn = tab.current.url.urn(); - let leave = matches!(op, FilesOp::Deleting(_, ref urns) if urns.contains(urn)); + let leave = matches!(op, FilesOp::Deleting(_, ref urns) if urns.contains(&urn)); if let Some(f) = tab.parent.as_mut() { render!(f.update_pub(tab.id, op)); @@ -102,7 +102,7 @@ impl UpdateFiles { fn update_history(cx: &mut Ctx, op: FilesOp) -> Result { let tab = &mut cx.tab_mut(); let leave = tab.parent.as_ref().and_then(|f| f.url.parent().map(|p| (p, f.url.urn()))).is_some_and( - |(p, n)| matches!(op, FilesOp::Deleting(ref parent, ref urns) if *parent == p && urns.contains(n)), + |(p, n)| matches!(op, FilesOp::Deleting(ref parent, ref urns) if *parent == p && urns.contains(&n)), ); tab diff --git a/yazi-binding/src/url.rs b/yazi-binding/src/url.rs index 46bb2d63..4c75f7ea 100644 --- a/yazi-binding/src/url.rs +++ b/yazi-binding/src/url.rs @@ -108,10 +108,7 @@ 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| { - // FIXME: remove type inference - Ok(super::Path::::new(me.urn())) - }); + cached_field!(fields, urn, |_, me| Ok(super::Path::new(me.urn()))); cached_field!(fields, base, |_, me| Ok(me.base().map(Self::new))); cached_field!(fields, scheme, |_, me| Ok(Scheme::new(&me.scheme))); @@ -168,8 +165,8 @@ impl UserData for Url { }); methods.add_method("strip_prefix", |_, me, base: Value| { let path = match base { - Value::String(s) => me.loc.strip_prefix(s.as_bytes().into_os_str()?).ok(), - Value::UserData(ud) => me.strip_prefix(&*ud.borrow::()?).map(AsRef::as_ref), + Value::String(s) => me.loc().strip_prefix(&s.as_bytes().into_os_str()?).map(Into::into), + Value::UserData(ud) => me.strip_prefix(&*ud.borrow::()?), _ => Err("must be a string or Url".into_lua_err())?, }; Ok(path.map(Self::new)) // TODO: return `Path` instead of `Url` diff --git a/yazi-binding/src/urn.rs b/yazi-binding/src/urn.rs index f770420e..6463ca87 100644 --- a/yazi-binding/src/urn.rs +++ b/yazi-binding/src/urn.rs @@ -1,30 +1,21 @@ -use std::{ops::Deref, path::PathBuf}; +use std::ops::Deref; use mlua::{ExternalError, FromLua, Lua, UserData, Value}; -use yazi_shared::path::PathBufLike; +use yazi_shared::path::PathBufDyn; -pub struct Path(pub P); +pub struct Path(pub PathBufDyn); -impl

Deref for Path

-where - P: PathBufLike, -{ - type Target = P; +impl Deref for Path { + type Target = PathBufDyn; fn deref(&self) -> &Self::Target { &self.0 } } -impl

Path

-where - P: PathBufLike, -{ - pub fn new(urn: impl Into

) -> Self { Self(urn.into()) } +impl Path { + pub fn new(urn: impl Into) -> Self { Self(urn.into()) } } -impl

FromLua for Path

-where - P: PathBufLike, -{ +impl FromLua for Path { fn from_lua(value: Value, _: &Lua) -> mlua::Result { Ok(match value { Value::UserData(ud) => ud.take()?, @@ -33,4 +24,4 @@ where } } -impl

UserData for Path

where P: PathBufLike {} +impl UserData for Path {} diff --git a/yazi-boot/src/boot.rs b/yazi-boot/src/boot.rs index 68f3610e..b08fb59d 100644 --- a/yazi-boot/src/boot.rs +++ b/yazi-boot/src/boot.rs @@ -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}; +use yazi_shared::{path::{PathBufDyn, PathLike}, url::{UrlBuf, UrlCow, UrlLike}}; use yazi_vfs::provider; #[derive(Debug, Default, Serialize)] pub struct Boot { pub cwds: Vec, - pub files: Vec, + pub files: Vec, pub local_events: HashSet, pub remote_events: HashSet, @@ -22,25 +22,25 @@ pub struct Boot { } impl Boot { - async fn parse_entries(entries: &[UrlBuf]) -> (Vec, Vec) { + async fn parse_entries(entries: &[UrlBuf]) -> (Vec, Vec) { if entries.is_empty() { - return (vec![CWD.load().as_ref().clone()], vec![PathBuf::default()]); + return (vec![CWD.load().as_ref().clone()], vec![PathBufDyn::os_default()]); } - async fn go(entry: &UrlBuf) -> (UrlBuf, PathBuf) { + async fn go(entry: &UrlBuf) -> (UrlBuf, PathBufDyn) { 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, PathBuf::default()); + return (entry, PathBufDyn::os_default()); }; if provider::metadata(&entry).await.is_ok_and(|m| m.is_file()) { - (parent.into(), child.to_owned()) + (parent.into(), child.owned()) } else { - (entry, PathBuf::default()) + (entry, PathBufDyn::os_default()) } } diff --git a/yazi-config/src/mgr/mgr.rs b/yazi-config/src/mgr/mgr.rs index 2796db07..6be3ebfb 100644 --- a/yazi-config/src/mgr/mgr.rs +++ b/yazi-config/src/mgr/mgr.rs @@ -2,7 +2,7 @@ use anyhow::{Result, bail}; use serde::Deserialize; use yazi_codegen::DeserializeOver2; use yazi_fs::{CWD, SortBy}; -use yazi_shared::{SyncCell, url::{UrlBuf, UrlLike}}; +use yazi_shared::{SyncCell, path::PathLike, url::{UrlBuf, UrlLike}}; use super::{MgrRatio, MouseEvents}; @@ -33,8 +33,8 @@ impl Mgr { } let home = UrlBuf::from(dirs::home_dir().unwrap_or_default()); - let cwd = if let Some(u) = CWD.load().strip_prefix(&home) { - format!("~{}{}", std::path::MAIN_SEPARATOR, u.display()) + let cwd = if let Some(p) = CWD.load().strip_prefix(&home) { + format!("~{}{}", std::path::MAIN_SEPARATOR, p.display()) } else { format!("{}", CWD.load().display()) }; diff --git a/yazi-core/src/tab/finder.rs b/yazi-core/src/tab/finder.rs index 509bbc46..4ba100f7 100644 --- a/yazi-core/src/tab/finder.rs +++ b/yazi-core/src/tab/finder.rs @@ -1,15 +1,13 @@ -use std::path::{Path, PathBuf}; - use anyhow::Result; use hashbrown::HashMap; use yazi_fs::{Files, Filter, FilterCase}; -use yazi_shared::url::UrlBuf; +use yazi_shared::{path::{AsPathDyn, PathBufDyn, PathLike}, url::UrlBuf}; use crate::tab::Folder; pub struct Finder { pub filter: Filter, - pub matched: HashMap, + pub matched: HashMap, lock: FinderLock, } @@ -64,7 +62,7 @@ impl Finder { continue; } - self.matched.insert(file.urn().to_owned(), i); + self.matched.insert(file.urn().owned(), i); if self.matched.len() > 99 { break; } @@ -78,8 +76,11 @@ impl Finder { } impl Finder { - pub fn matched_idx(&self, folder: &Folder, urn: &Path) -> Option { - if self.lock == *folder { self.matched.get(urn).copied() } else { None } + pub fn matched_idx(&self, folder: &Folder, urn: T) -> Option + where + T: AsPathDyn, + { + if self.lock == *folder { self.matched.get(&urn.as_path_dyn()).copied() } else { None } } } diff --git a/yazi-core/src/tab/folder.rs b/yazi-core/src/tab/folder.rs index 2a2cc6ba..51eabad5 100644 --- a/yazi-core/src/tab/folder.rs +++ b/yazi-core/src/tab/folder.rs @@ -1,4 +1,4 @@ -use std::{mem, path::{Path, PathBuf}}; +use std::mem; 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}; +use yazi_shared::{Id, path::{PathBufDyn, PathBufLike, PathDyn, PathLike}, 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, + pub trace: Option, } impl Default for Folder { @@ -101,14 +101,14 @@ impl Folder { self.scroll(step) }; - self.trace = self.hovered().filter(|_| b).map(|h| h.urn().to_owned()).or(self.trace.take()); + self.trace = self.hovered().filter(|_| b).map(|h| h.urn().owned()).or(self.trace.take()); b |= self.squeeze_offset(); self.sync_page(false); b } - pub fn hover(&mut self, urn: &Path) -> bool { + pub fn hover(&mut self, urn: PathDyn) -> bool { if self.hovered().map(|h| h.urn()) == Some(urn) { return self.arrow(0); } @@ -117,11 +117,11 @@ impl Folder { self.arrow(new - self.cursor as isize) } - pub fn repos(&mut self, urn: Option<&Path>) -> bool { + pub fn repos(&mut self, urn: Option) -> bool { if let Some(u) = urn { self.hover(u) } else if let Some(u) = &self.trace { - self.hover(&u.clone()) + self.hover(u.clone().borrow()) } else { self.arrow(0) } diff --git a/yazi-core/src/tasks/prework.rs b/yazi-core/src/tasks/prework.rs index d44c6136..096caf56 100644 --- a/yazi-core/src/tasks/prework.rs +++ b/yazi-core/src/tasks/prework.rs @@ -52,7 +52,9 @@ impl Tasks { let loading = self.scheduler.prework.sizing.read(); targets .iter() - .filter(|f| f.is_dir() && !targets.sizes.contains_key(f.urn()) && !loading.contains(&f.url)) + .filter(|f| { + f.is_dir() && !targets.sizes.contains_key(&f.urn()) && !loading.contains(&f.url) + }) .map(|f| &f.url) .collect() }; diff --git a/yazi-dds/src/sendable.rs b/yazi-dds/src/sendable.rs index 157e6b94..c04b6af7 100644 --- a/yazi-dds/src/sendable.rs +++ b/yazi-dds/src/sendable.rs @@ -46,8 +46,8 @@ impl Sendable { Some(t) if t == TypeId::of::() => { Data::Url(ud.take::()?.into()) } - Some(t) if t == TypeId::of::>() => { - Data::Path(ud.take::>()?.0) + Some(t) if t == TypeId::of::() => { + Data::Path(ud.take::()?.0) } Some(t) if t == TypeId::of::() => { Data::Id(**ud.borrow::()?) @@ -83,7 +83,7 @@ impl Sendable { Value::Table(tbl) } Data::Url(u) => yazi_binding::Url::new(u).into_lua(lua)?, - Data::Path(u) => yazi_binding::Path::::new(u).into_lua(lua)?, + Data::Path(u) => yazi_binding::Path::new(u).into_lua(lua)?, Data::Any(a) => { if a.is::() { lua.create_any_userdata(*a.downcast::().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::Path(u) => yazi_binding::Path::::new(u).into_lua(lua)?, + Data::Path(u) => yazi_binding::Path::new(u).into_lua(lua)?, Data::Bytes(b) => Value::String(lua.create_string(b)?), Data::Any(a) => { if let Some(t) = a.downcast_ref::() { @@ -230,7 +230,7 @@ impl Sendable { fn key_to_value(lua: &Lua, key: DataKey) -> mlua::Result { match key { DataKey::Url(u) => yazi_binding::Url::new(u).into_lua(lua), - DataKey::Path(u) => yazi_binding::Path::::new(u).into_lua(lua), + DataKey::Path(u) => yazi_binding::Path::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::Path(u) => yazi_binding::Path::::new(u).into_lua(lua)?, + DataKey::Path(u) => yazi_binding::Path::new(u).into_lua(lua)?, DataKey::Bytes(b) => Value::String(lua.create_string(b)?), }) } diff --git a/yazi-fm/src/app/commands/bootstrap.rs b/yazi-fm/src/app/commands/bootstrap.rs index c8b3cb03..574906a5 100644 --- a/yazi-fm/src/app/commands/bootstrap.rs +++ b/yazi-fm/src/app/commands/bootstrap.rs @@ -3,7 +3,7 @@ use yazi_actor::Ctx; use yazi_boot::BOOT; use yazi_macro::act; use yazi_parser::{VoidOpt, mgr::CdSource}; -use yazi_shared::{data::Data, url::UrlLike}; +use yazi_shared::{data::Data, path::PathBufLike, url::UrlLike}; use crate::app::App; @@ -18,7 +18,7 @@ impl App { let cx = &mut Ctx::active(&mut self.core); cx.tab = i; - if file.as_os_str().is_empty() { + if file.is_empty() { act!(mgr:cd, cx, (BOOT.cwds[i].clone(), CdSource::Tab))?; } else { act!(mgr:reveal, cx, (BOOT.cwds[i].join(file), CdSource::Tab))?; diff --git a/yazi-fs/src/file.rs b/yazi-fs/src/file.rs index 0d60bb83..771bd0fc 100644 --- a/yazi-fs/src/file.rs +++ b/yazi-fs/src/file.rs @@ -40,7 +40,7 @@ impl File { pub fn uri(&self) -> PathDyn<'_> { self.url.uri() } #[inline] - pub fn urn(&self) -> &Path { self.url.urn() } + pub fn urn(&self) -> PathDyn<'_> { self.url.urn() } #[inline] pub fn name(&self) -> Option<&OsStr> { self.url.name() } diff --git a/yazi-fs/src/files.rs b/yazi-fs/src/files.rs index 67e59754..557c4891 100644 --- a/yazi-fs/src/files.rs +++ b/yazi-fs/src/files.rs @@ -1,7 +1,7 @@ -use std::{mem, ops::{Deref, DerefMut, Not}, path::{Path, PathBuf}}; +use std::{mem, ops::{Deref, DerefMut, Not}}; use hashbrown::{HashMap, HashSet}; -use yazi_shared::Id; +use yazi_shared::{Id, path::{PathBufDyn, PathBufLike, PathDyn, PathLike}}; 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, + pub sizes: HashMap, sorter: FilesSorter, filter: Option, @@ -69,7 +69,7 @@ impl Files { } } - pub fn update_size(&mut self, mut sizes: HashMap) { + pub fn update_size(&mut self, mut sizes: HashMap) { if sizes.len() <= 50 { sizes.retain(|k, v| self.sizes.get(k) != Some(v)); } @@ -97,9 +97,9 @@ impl Files { macro_rules! go { ($dist:expr, $src:expr, $inc:literal) => { - let mut todo: HashMap<_, _> = $src.into_iter().map(|f| (f.urn().to_owned(), f)).collect(); + let mut todo: HashMap<_, _> = $src.into_iter().map(|f| (f.urn().owned(), f)).collect(); for f in &$dist { - if todo.remove(f.urn()).is_some() && todo.is_empty() { + if todo.remove(&f.urn()).is_some() && todo.is_empty() { break; } } @@ -120,25 +120,26 @@ impl Files { } #[cfg(unix)] - pub fn update_deleting(&mut self, urns: HashSet) -> Vec { - use yazi_shared::path::PathLike; + pub fn update_deleting(&mut self, urns: HashSet) -> Vec { 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.is_hidden()) || !filter.matches(u)) + urns + .into_iter() + .partition(|u| (!self.show_hidden && u.borrow().is_hidden()) || !filter.matches(u)) } else if self.show_hidden { (HashSet::new(), urns) } else { - urns.into_iter().partition(|u| u.is_hidden()) + urns.into_iter().partition(|u| u.borrow().is_hidden()) }; let mut deleted = Vec::with_capacity(items.len()); if !items.is_empty() { let mut i = 0; self.items.retain(|f| { - let b = items.remove(f.urn()); + let b = items.remove(&f.urn()); if b { deleted.push(i); } @@ -147,7 +148,7 @@ impl Files { }); } if !hidden.is_empty() { - self.hidden.retain(|f| !hidden.remove(f.urn())); + self.hidden.retain(|f| !hidden.remove(&f.urn())); } self.revision += deleted.is_empty().not() as u64; @@ -155,12 +156,12 @@ impl Files { } #[cfg(windows)] - pub fn update_deleting(&mut self, mut urns: HashSet) -> Vec { + pub fn update_deleting(&mut self, mut urns: HashSet) -> Vec { let mut deleted = Vec::with_capacity(urns.len()); if !urns.is_empty() { let mut i = 0; self.items.retain(|f| { - let b = urns.remove(f.urn()); + let b = urns.remove(&f.urn()); if b { deleted.push(i) } @@ -169,7 +170,7 @@ impl Files { }); } if !urns.is_empty() { - self.hidden.retain(|f| !urns.remove(f.urn())); + self.hidden.retain(|f| !urns.remove(&f.urn())); } self.revision += deleted.is_empty().not() as u64; @@ -178,8 +179,8 @@ impl Files { pub fn update_updating( &mut self, - files: HashMap, - ) -> (HashMap, HashMap) { + files: HashMap, + ) -> (HashMap, HashMap) { if files.is_empty() { return Default::default(); } @@ -188,7 +189,7 @@ impl Files { ($dist:expr, $src:expr, $inc:literal) => { let mut b = true; for i in 0..$dist.len() { - if let Some(f) = $src.remove($dist[i].urn()) { + if let Some(f) = $src.remove(&$dist[i].urn()) { b = b && $dist[i].cha.hits(f.cha); b = b && $dist[i].urn() == f.urn(); @@ -221,13 +222,13 @@ impl Files { (hidden, items) } - pub fn update_upserting(&mut self, files: HashMap) { + pub fn update_upserting(&mut self, files: HashMap) { if files.is_empty() { return; } self.update_deleting( - files.iter().filter(|&(u, f)| u != f.urn()).map(|(_, f)| f.urn().to_owned()).collect(), + files.iter().filter(|&(u, f)| u != f.urn()).map(|(_, f)| f.urn().owned()).collect(), ); let (hidden, items) = self.update_updating(files); @@ -270,7 +271,7 @@ impl Files { impl Files { // --- Items #[inline] - pub fn position(&self, urn: &Path) -> Option { self.iter().position(|f| urn == f.urn()) } + pub fn position(&self, urn: PathDyn) -> Option { self.iter().position(|f| urn == f.urn()) } // --- Ticket #[inline] diff --git a/yazi-fs/src/op.rs b/yazi-fs/src/op.rs index ed9414a8..0e5d82b2 100644 --- a/yazi-fs/src/op.rs +++ b/yazi-fs/src/op.rs @@ -1,8 +1,8 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use hashbrown::{HashMap, HashSet}; use yazi_macro::relay; -use yazi_shared::{Id, Ids, url::{UrlBuf, UrlLike}}; +use yazi_shared::{Id, Ids, path::{PathBufDyn, PathLike}, url::{UrlBuf, UrlLike}}; use super::File; use crate::{cha::Cha, error::Error}; @@ -14,13 +14,13 @@ pub enum FilesOp { Full(UrlBuf, Vec, Cha), Part(UrlBuf, Vec, Id), Done(UrlBuf, Cha, Id), - Size(UrlBuf, HashMap), + Size(UrlBuf, HashMap), IOErr(UrlBuf, Error), Creating(UrlBuf, Vec), - Deleting(UrlBuf, HashSet), - Updating(UrlBuf, HashMap), - Upserting(UrlBuf, HashMap), + Deleting(UrlBuf, HashSet), + Updating(UrlBuf, HashMap), + Upserting(UrlBuf, HashMap), } impl FilesOp { @@ -57,10 +57,10 @@ impl FilesOp { let Some(o_p) = o.parent() else { continue }; let Some(n_p) = n.url.parent() else { continue }; if o_p == n_p { - parents.entry_ref(&o_p).or_default().1.insert(o.urn().to_owned(), n); + parents.entry_ref(&o_p).or_default().1.insert(o.urn().owned(), n); } else { - parents.entry_ref(&o_p).or_default().0.insert(o.urn().to_owned()); - parents.entry_ref(&n_p).or_default().1.insert(n.urn().to_owned(), n); + parents.entry_ref(&o_p).or_default().0.insert(o.urn().owned()); + parents.entry_ref(&n_p).or_default().1.insert(n.urn().owned(), n); } } for (p, (o, n)) in parents { diff --git a/yazi-fs/src/sorter.rs b/yazi-fs/src/sorter.rs index cd7ede81..8d85e020 100644 --- a/yazi-fs/src/sorter.rs +++ b/yazi-fs/src/sorter.rs @@ -1,7 +1,7 @@ -use std::{cmp::Ordering, path::PathBuf}; +use std::cmp::Ordering; use hashbrown::HashMap; -use yazi_shared::{LcgRng, natsort, path::PathLike, translit::Transliterator, url::UrlLike}; +use yazi_shared::{LcgRng, natsort, path::{PathBufDyn, 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) { + pub(super) fn sort(&self, items: &mut [File], sizes: &HashMap) { if items.is_empty() { return; } @@ -53,8 +53,8 @@ impl FilesSorter { SortBy::Alphabetical => items.sort_unstable_by(by_alphabetical), SortBy::Natural => self.sort_naturally(items), SortBy::Size => items.sort_unstable_by(|a, b| { - let aa = if a.is_dir() { sizes.get(a.urn()).copied() } else { None }; - let bb = if b.is_dir() { sizes.get(b.urn()).copied() } else { None }; + let aa = if a.is_dir() { sizes.get(&a.urn()).copied() } else { None }; + let bb = if b.is_dir() { sizes.get(&b.urn()).copied() } else { None }; let ord = self.cmp(aa.unwrap_or(a.len), bb.unwrap_or(b.len), self.promote(a, b)); if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord } }), diff --git a/yazi-parser/src/mgr/hover.rs b/yazi-parser/src/mgr/hover.rs index 359a2659..d4ab068d 100644 --- a/yazi-parser/src/mgr/hover.rs +++ b/yazi-parser/src/mgr/hover.rs @@ -1,14 +1,13 @@ -use std::path::PathBuf; - use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; +use yazi_shared::path::PathBufDyn; #[derive(Debug, Default)] pub struct HoverOpt { - pub urn: Option, + pub urn: Option, } -impl From> for HoverOpt { - fn from(urn: Option) -> Self { Self { urn } } +impl From> for HoverOpt { + fn from(urn: Option) -> Self { Self { urn } } } impl FromLua for HoverOpt { diff --git a/yazi-scheduler/src/prework/prework.rs b/yazi-scheduler/src/prework/prework.rs index 209a2728..c9ec0aa0 100644 --- a/yazi-scheduler/src/prework/prework.rs +++ b/yazi-scheduler/src/prework/prework.rs @@ -10,7 +10,7 @@ use tracing::error; use yazi_config::Priority; use yazi_fs::{FilesOp, FsHash64}; use yazi_plugin::isolate; -use yazi_shared::{event::CmdCow, url::{UrlBuf, UrlLike}}; +use yazi_shared::{event::CmdCow, path::PathLike, url::{UrlBuf, UrlLike}}; use yazi_vfs::provider; use super::{PreworkInFetch, PreworkInLoad, PreworkInSize}; @@ -106,7 +106,7 @@ impl Prework { let parent = buf[0].0.parent().unwrap(); FilesOp::Size( parent.into(), - HashMap::from_iter(buf.into_iter().map(|(u, s)| (u.urn().to_owned(), s))), + HashMap::from_iter(buf.into_iter().map(|(u, s)| (u.urn().owned(), s))), ) .emit(); }); diff --git a/yazi-shared/Cargo.toml b/yazi-shared/Cargo.toml index ec42c45a..9c14365e 100644 --- a/yazi-shared/Cargo.toml +++ b/yazi-shared/Cargo.toml @@ -7,7 +7,7 @@ authors = [ "sxyazi " ] description = "Yazi shared library" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" -rust-version = "1.88.0" +rust-version = "1.91.0" [dependencies] yazi-macro = { path = "../yazi-macro", version = "25.9.15" } diff --git a/yazi-shared/src/data/data.rs b/yazi-shared/src/data/data.rs index 856ce226..bc82c1e9 100644 --- a/yazi-shared/src/data/data.rs +++ b/yazi-shared/src/data/data.rs @@ -1,10 +1,10 @@ -use std::{any::Any, borrow::Cow, path::PathBuf}; +use std::{any::Any, borrow::Cow}; use anyhow::{Result, bail}; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; -use crate::{Id, SStr, data::DataKey, url::{UrlBuf, UrlCow}}; +use crate::{Id, SStr, data::DataKey, path::PathBufDyn, url::{UrlBuf, UrlCow}}; // --- Data #[derive(Debug, Deserialize, Serialize)] @@ -21,7 +21,7 @@ pub enum Data { #[serde(skip_deserializing)] Url(UrlBuf), #[serde(skip_deserializing)] - Path(PathBuf), + Path(PathBufDyn), #[serde(skip)] Bytes(Vec), #[serde(skip)] diff --git a/yazi-shared/src/data/key.rs b/yazi-shared/src/data/key.rs index ac67a8f1..005416ac 100644 --- a/yazi-shared/src/data/key.rs +++ b/yazi-shared/src/data/key.rs @@ -1,9 +1,9 @@ -use std::{borrow::Cow, path::PathBuf}; +use std::borrow::Cow; use ordered_float::OrderedFloat; use serde::{Deserialize, Serialize, de}; -use crate::{Id, SStr, url::{UrlBuf, UrlCow}}; +use crate::{Id, SStr, path::PathBufDyn, 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)] - Path(PathBuf), + Path(PathBufDyn), #[serde(skip)] Bytes(Vec), } diff --git a/yazi-shared/src/loc/buf.rs b/yazi-shared/src/loc/buf.rs index 5efd399d..5e669c6c 100644 --- a/yazi-shared/src/loc/buf.rs +++ b/yazi-shared/src/loc/buf.rs @@ -2,7 +2,7 @@ use std::{cmp, ffi::OsStr, fmt::{self, Debug, Formatter}, hash::{Hash, Hasher}, use anyhow::Result; -use crate::{loc::Loc, path::{AsInnerView, AsPathView, PathBufLike, PathLike}}; +use crate::{loc::Loc, path::{AsInnerView, AsPathDyn, AsPathView, PathBufLike, PathDyn, PathLike}}; #[derive(Clone, Default, Eq)] pub struct LocBuf { @@ -25,6 +25,20 @@ impl AsRef for LocBuf { fn as_ref(&self) -> &std::path::Path { self.inner.as_ref() } } +impl AsPathDyn for LocBuf +where + T: PathBufLike + AsPathDyn, +{ + fn as_path_dyn(&self) -> PathDyn<'_> { self.inner.as_path_dyn() } +} + +impl AsPathDyn for &LocBuf +where + T: PathBufLike + AsPathDyn, +{ + fn as_path_dyn(&self) -> PathDyn<'_> { self.inner.as_path_dyn() } +} + impl

PartialEq for LocBuf

where P: PathBufLike + PartialEq, @@ -117,10 +131,6 @@ where Ok(Self { inner: loc.inner, uri, urn }) } - // FIXME: use `LocBuf::empty()` when Rust 1.91.0 released - // pub const fn empty() -> Self { Self { inner: PathBuf::new(), uri: 0, urn: 0 } - // } - pub fn zeroed(path: T) -> Self where T: Into

, @@ -245,6 +255,10 @@ where pub fn ext(&self) -> Option< as PathLike<'_>>::Inner> { self.as_loc().ext() } } +impl LocBuf { + pub const fn empty() -> Self { Self { inner: PathBuf::new(), uri: 0, urn: 0 } } +} + #[cfg(test)] mod tests { use std::path::Path; diff --git a/yazi-shared/src/loc/loc.rs b/yazi-shared/src/loc/loc.rs index 06138a9b..9d3697a7 100644 --- a/yazi-shared/src/loc/loc.rs +++ b/yazi-shared/src/loc/loc.rs @@ -2,7 +2,7 @@ use std::{hash::{Hash, Hasher}, marker::PhantomData, ops::Deref, path::Path}; use anyhow::{Result, bail}; -use crate::{loc::LocBuf, path::{AsPathView, PathBufLike, PathInner, PathLike, ToPathOwned}}; +use crate::{loc::LocBuf, path::{AsPathView, PathBufLike, PathInner, PathLike}}; #[derive(Clone, Copy, Debug)] pub struct Loc<'p, P = &'p Path> { @@ -43,11 +43,11 @@ where impl<'p, P> From> for LocBuf<

>::Owned> where - P: PathLike<'p> + ToPathOwned<

>::Owned>, + P: PathLike<'p>,

>::Owned: PathBufLike, { fn from(value: Loc<'p, P>) -> Self { - Self { inner: value.inner.to_path_owned(), uri: value.uri, urn: value.urn } + Self { inner: value.inner.owned(), uri: value.uri, urn: value.urn } } } diff --git a/yazi-shared/src/path/buf.rs b/yazi-shared/src/path/buf.rs index e3790201..7e3ff236 100644 --- a/yazi-shared/src/path/buf.rs +++ b/yazi-shared/src/path/buf.rs @@ -10,12 +10,16 @@ where type InnerRef<'a>: PathInner<'a>; type Borrowed<'a>: PathLike<'a> + AsPathView<'a, Self::Borrowed<'a>> + Debug + Hash; + fn borrow(&self) -> Self::Borrowed<'_>; + fn encoded_bytes(&self) -> &[u8]; unsafe fn from_encoded_bytes(bytes: Vec) -> Self; fn into_encoded_bytes(self) -> Vec; + fn is_empty(&self) -> bool { self.encoded_bytes().is_empty() } + fn len(&self) -> usize { self.encoded_bytes().len() } fn set_file_name(&mut self, name: T) @@ -30,6 +34,8 @@ impl PathBufLike for std::path::PathBuf { type Inner = std::ffi::OsString; type InnerRef<'a> = &'a std::ffi::OsStr; + fn borrow(&self) -> Self::Borrowed<'_> { self.as_path() } + fn encoded_bytes(&self) -> &[u8] { self.as_os_str().as_encoded_bytes() } unsafe fn from_encoded_bytes(bytes: Vec) -> Self { diff --git a/yazi-shared/src/path/dyn.rs b/yazi-shared/src/path/dyn.rs index 078d724a..10f32014 100644 --- a/yazi-shared/src/path/dyn.rs +++ b/yazi-shared/src/path/dyn.rs @@ -1,3 +1,6 @@ +use hashbrown::Equivalent; +use serde::Serialize; + use super::{AsInnerView, AsPathView}; use crate::path::{PathBufLike, PathLike}; @@ -18,8 +21,13 @@ impl<'a> From<&'a std::path::Path> for PathDyn<'a> { fn from(value: &'a std::path::Path) -> Self { PathDyn::Os(value) } } +impl<'a> From<&'a PathBufDyn> for PathDyn<'a> { + fn from(value: &'a PathBufDyn) -> Self { value.borrow() } +} + impl<'p> PathLike<'p> for PathDyn<'p> { type Components<'a> = std::path::Components<'a>; + type Display<'a> = std::path::Display<'a>; type Inner = &'p [u8]; type Owned = PathBufDyn; type View<'a> = PathDyn<'a>; @@ -33,6 +41,12 @@ impl<'p> PathLike<'p> for PathDyn<'p> { // FIXME: remove fn default() -> Self { Self::Os(std::path::Path::new("")) } + fn display(self) -> Self::Display<'p> { + match self { + Self::Os(p) => p.display(), + } + } + fn encoded_bytes(self) -> &'p [u8] { match self { Self::Os(p) => p.as_os_str().as_encoded_bytes(), @@ -71,6 +85,12 @@ impl<'p> PathLike<'p> for PathDyn<'p> { } } + fn owned(self) -> Self::Owned { + match self { + Self::Os(p) => Self::Owned::Os(p.to_path_buf()), + } + } + fn parent(self) -> Option { Some(match self { Self::Os(p) => Self::Os(p.parent()?), @@ -87,16 +107,40 @@ impl<'p> PathLike<'p> for PathDyn<'p> { } } -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +impl PartialEq for PathDyn<'_> { + fn eq(&self, other: &PathBufDyn) -> bool { *self == other.borrow() } +} + +impl PartialEq> for &std::path::Path { + fn eq(&self, other: &PathDyn<'_>) -> bool { matches!(*other, PathDyn::Os(p) if p == *self) } +} + +impl Equivalent for PathDyn<'_> { + fn equivalent(&self, key: &PathBufDyn) -> bool { *self == key.borrow() } +} + +// --- PathBufDyn +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +#[serde(untagged)] pub enum PathBufDyn { Os(std::path::PathBuf), } +impl PathBufDyn { + pub const fn os_default() -> Self { Self::Os(std::path::PathBuf::new()) } +} + impl PathBufLike for PathBufDyn { type Borrowed<'a> = PathDyn<'a>; type Inner = Vec; type InnerRef<'a> = &'a [u8]; + fn borrow(&self) -> Self::Borrowed<'_> { + match self { + Self::Os(p) => Self::Borrowed::Os(p.as_path()), + } + } + fn encoded_bytes(&self) -> &[u8] { match self { Self::Os(p) => p.as_os_str().as_encoded_bytes(), @@ -130,3 +174,27 @@ impl PathBufLike for PathBufDyn { } } } + +impl From> for PathBufDyn { + fn from(value: PathDyn<'_>) -> Self { + match value { + PathDyn::Os(p) => Self::Os(p.to_path_buf()), + } + } +} + +impl From<&PathBufDyn> for PathBufDyn { + fn from(value: &PathBufDyn) -> Self { value.clone() } +} + +impl PartialEq> for PathBufDyn { + fn eq(&self, other: &PathDyn<'_>) -> bool { self.borrow() == *other } +} + +impl PartialEq> for &PathBufDyn { + fn eq(&self, other: &PathDyn<'_>) -> bool { self.borrow() == *other } +} + +impl Equivalent> for PathBufDyn { + fn equivalent(&self, key: &PathDyn<'_>) -> bool { self.borrow() == *key } +} diff --git a/yazi-shared/src/path/inner.rs b/yazi-shared/src/path/inner.rs index 741bd624..4237078a 100644 --- a/yazi-shared/src/path/inner.rs +++ b/yazi-shared/src/path/inner.rs @@ -1,7 +1,9 @@ pub trait PathInner<'a>: Copy { - fn len(self) -> usize { self.encoded_bytes().len() } - fn encoded_bytes(self) -> &'a [u8]; + + fn is_empty(self) -> bool { self.encoded_bytes().is_empty() } + + fn len(self) -> usize { self.encoded_bytes().len() } } impl<'a> PathInner<'a> for &'a std::ffi::OsStr { diff --git a/yazi-shared/src/path/path.rs b/yazi-shared/src/path/path.rs index 3a2e23f3..51e83577 100644 --- a/yazi-shared/src/path/path.rs +++ b/yazi-shared/src/path/path.rs @@ -8,11 +8,14 @@ where type Owned: PathBufLike + Into; type View<'a>; type Components<'a>: AsPathView<'a, Self::View<'a>> + Clone + DoubleEndedIterator; + type Display<'a>: std::fmt::Display; fn components(self) -> Self::Components<'p>; fn default() -> Self; + fn display(self) -> Self::Display<'p>; + fn encoded_bytes(self) -> &'p [u8]; fn extension(self) -> Option; @@ -27,7 +30,7 @@ where #[cfg(unix)] fn is_hidden(self) -> bool { - self.file_name().map_or(false, |n| n.encoded_bytes().get(0) == Some(&b'.')) + self.file_name().is_some_and(|n| n.encoded_bytes().first() == Some(&b'.')) } fn join<'a, T>(self, base: T) -> Self::Owned @@ -36,6 +39,8 @@ where fn len(self) -> usize { self.encoded_bytes().len() } + fn owned(self) -> Self::Owned; + fn parent(self) -> Option; fn strip_prefix<'a, T>(self, base: T) -> Option @@ -45,6 +50,7 @@ where impl<'p> PathLike<'p> for &'p std::path::Path { type Components<'a> = std::path::Components<'a>; + type Display<'a> = std::path::Display<'a>; type Inner = &'p std::ffi::OsStr; type Owned = std::path::PathBuf; type View<'a> = &'a std::path::Path; @@ -53,6 +59,8 @@ impl<'p> PathLike<'p> for &'p std::path::Path { fn default() -> Self { std::path::Path::new("") } + fn display(self) -> Self::Display<'p> { self.display() } + fn encoded_bytes(self) -> &'p [u8] { self.as_os_str().as_encoded_bytes() } fn extension(self) -> Option { self.extension() } @@ -72,6 +80,8 @@ impl<'p> PathLike<'p> for &'p std::path::Path { self.join(base.as_path_view()) } + fn owned(self) -> Self::Owned { self.to_path_buf() } + fn parent(self) -> Option { self.parent() } fn strip_prefix<'a, T>(self, base: T) -> Option diff --git a/yazi-shared/src/path/traits.rs b/yazi-shared/src/path/traits.rs index 5b1d636b..f24f1c4d 100644 --- a/yazi-shared/src/path/traits.rs +++ b/yazi-shared/src/path/traits.rs @@ -1,23 +1,87 @@ -use crate::path::PathLike; +use std::{borrow::Cow, ffi::{OsStr, OsString}}; + +use super::{PathBufDyn, PathDyn}; +use crate::path::{PathBufLike, PathLike}; pub trait AsPath { fn as_path(&self) -> impl PathLike<'_>; } -impl AsPath for &std::ffi::OsStr { +impl AsPath for OsStr { fn as_path(&self) -> impl PathLike<'_> { std::path::Path::new(self) } } -impl AsPath for &std::path::Path { - fn as_path(&self) -> impl PathLike<'_> { *self } +impl AsPath for &OsStr { + fn as_path(&self) -> impl PathLike<'_> { std::path::Path::new(self) } +} + +impl AsPath for std::path::Path { + fn as_path(&self) -> impl PathLike<'_> { self } } impl AsPath for std::path::PathBuf { fn as_path(&self) -> impl PathLike<'_> { self.as_path() } } -impl AsPath for &std::path::PathBuf { - fn as_path(&self) -> impl PathLike<'_> { (*self).as_path() } +impl AsPath for PathDyn<'_> { + fn as_path(&self) -> impl PathLike<'_> { *self } +} + +impl AsPath for PathBufDyn { + fn as_path(&self) -> impl PathLike<'_> { self.borrow() } +} + +impl AsPath for &PathBufDyn { + fn as_path(&self) -> impl PathLike<'_> { self.borrow() } +} + +// --- AsPathDyn +pub trait AsPathDyn { + fn as_path_dyn(&self) -> PathDyn<'_>; +} + +impl AsPathDyn for &str { + fn as_path_dyn(&self) -> PathDyn<'_> { std::path::Path::new(self).into() } +} + +impl AsPathDyn for String { + fn as_path_dyn(&self) -> PathDyn<'_> { std::path::Path::new(self).into() } +} + +impl AsPathDyn for &String { + fn as_path_dyn(&self) -> PathDyn<'_> { std::path::Path::new(self).into() } +} + +impl AsPathDyn for OsStr { + fn as_path_dyn(&self) -> PathDyn<'_> { std::path::Path::new(self).into() } +} + +impl AsPathDyn for &OsStr { + fn as_path_dyn(&self) -> PathDyn<'_> { std::path::Path::new(self).into() } +} + +impl AsPathDyn for Cow<'_, OsStr> { + fn as_path_dyn(&self) -> PathDyn<'_> { std::path::Path::new(self).into() } +} + +impl AsPathDyn for std::path::PathBuf { + fn as_path_dyn(&self) -> PathDyn<'_> { self.as_path().into() } +} + +impl AsPathDyn for &std::path::PathBuf { + fn as_path_dyn(&self) -> PathDyn<'_> { self.as_path().into() } +} + +impl AsPathDyn for PathDyn<'_> { + fn as_path_dyn(&self) -> PathDyn<'_> { *self } +} + +impl AsPathDyn for PathBufDyn { + fn as_path_dyn(&self) -> PathDyn<'_> { self.borrow() } +} + +impl AsPathDyn for &PathBufDyn { + fn as_path_dyn(&self) -> PathDyn<'_> { self.borrow() } } // --- AsPathView @@ -29,6 +93,10 @@ impl<'a> AsPathView<'a, &'a std::path::Path> for &'a str { fn as_path_view(self) -> &'a std::path::Path { std::path::Path::new(self) } } +impl<'a> AsPathView<'a, &'a std::path::Path> for &'a OsStr { + fn as_path_view(self) -> &'a std::path::Path { std::path::Path::new(self) } +} + impl<'a> AsPathView<'a, &'a std::path::Path> for &'a std::path::Path { fn as_path_view(self) -> &'a std::path::Path { self } } @@ -41,45 +109,33 @@ impl<'a> AsPathView<'a, &'a std::path::Path> for std::path::Components<'a> { fn as_path_view(self) -> &'a std::path::Path { self.as_path() } } -impl<'a> AsPathView<'a, super::PathDyn<'a>> for &'a super::PathBufDyn { - fn as_path_view(self) -> super::PathDyn<'a> { +impl<'a> AsPathView<'a, PathDyn<'a>> for &'a PathBufDyn { + fn as_path_view(self) -> PathDyn<'a> { match self { - super::PathBufDyn::Os(p) => super::PathDyn::Os(p.as_path()), + PathBufDyn::Os(p) => PathDyn::Os(p.as_path()), } } } +impl<'a> AsPathView<'a, &'a std::path::Path> for &'a Cow<'_, OsStr> { + fn as_path_view(self) -> &'a std::path::Path { std::path::Path::new(self) } +} + impl<'a> AsPathView<'a, &'a std::path::Path> for crate::loc::Loc<'a, &'a std::path::Path> { fn as_path_view(self) -> &'a std::path::Path { *self } } -// --- ToPathOwned -pub trait ToPathOwned { - fn to_path_owned(&self) -> T; -} - -impl ToPathOwned for std::path::Path { - fn to_path_owned(&self) -> std::path::PathBuf { self.to_owned() } -} - -impl ToPathOwned for &T -where - T: ?Sized + ToPathOwned, -{ - fn to_path_owned(&self) -> U { (*self).to_path_owned() } -} - // --- AsInnerView pub trait AsInnerView<'a, T> { fn as_inner_view(&'a self) -> T; } -impl<'a> AsInnerView<'a, &'a std::ffi::OsStr> for std::ffi::OsStr { - fn as_inner_view(&'a self) -> &'a std::ffi::OsStr { self } +impl<'a> AsInnerView<'a, &'a OsStr> for OsStr { + fn as_inner_view(&'a self) -> &'a OsStr { self } } -impl<'a> AsInnerView<'a, &'a std::ffi::OsStr> for std::ffi::OsString { - fn as_inner_view(&'a self) -> &'a std::ffi::OsStr { self } +impl<'a> AsInnerView<'a, &'a OsStr> for OsString { + fn as_inner_view(&'a self) -> &'a OsStr { self } } impl<'a> AsInnerView<'a, &'a [u8]> for [u8] { diff --git a/yazi-shared/src/url/buf.rs b/yazi-shared/src/url/buf.rs index 59fe12b7..1120a3d4 100644 --- a/yazi-shared/src/url/buf.rs +++ b/yazi-shared/src/url/buf.rs @@ -1,9 +1,9 @@ -use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::{Path, PathBuf}, str::FromStr, sync::OnceLock}; +use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::{Path, PathBuf}, str::FromStr}; use anyhow::Result; use serde::{Deserialize, Serialize}; -use crate::{loc::LocBuf, pool::Pool, scheme::{Scheme, SchemeLike}, url::{AsUrl, Encode, EncodeTilded, Url, UrlCow}}; +use crate::{loc::{Loc, LocBuf}, path::PathDyn, pool::Pool, scheme::{Scheme, SchemeLike}, url::{AsUrl, Encode, EncodeTilded, Url, UrlCow}}; #[derive(Clone, Default, Eq, Hash, PartialEq)] pub struct UrlBuf { @@ -11,6 +11,18 @@ pub struct UrlBuf { pub scheme: Scheme, } +impl From<&UrlBuf> for UrlBuf { + fn from(url: &UrlBuf) -> Self { url.clone() } +} + +impl From> for UrlBuf { + fn from(url: Url<'_>) -> Self { Self { loc: url.loc.into(), scheme: url.scheme.into() } } +} + +impl From<&Url<'_>> for UrlBuf { + fn from(url: &Url<'_>) -> Self { Self { loc: url.loc.into(), scheme: url.scheme.into() } } +} + impl From for UrlBuf { fn from(loc: LocBuf) -> Self { Self { loc, scheme: Scheme::Regular } } } @@ -19,18 +31,6 @@ impl From for UrlBuf { fn from(path: PathBuf) -> Self { LocBuf::from(path).into() } } -impl From<&Url<'_>> for UrlBuf { - fn from(url: &Url<'_>) -> Self { Self { loc: url.loc.into(), scheme: url.scheme.into() } } -} - -impl From> for UrlBuf { - fn from(url: Url<'_>) -> Self { Self { loc: url.loc.into(), scheme: url.scheme.into() } } -} - -impl From<&Self> for UrlBuf { - fn from(url: &Self) -> Self { url.clone() } -} - impl From<&PathBuf> for UrlBuf { fn from(path: &PathBuf) -> Self { path.to_owned().into() } } @@ -39,6 +39,14 @@ impl From<&Path> for UrlBuf { fn from(path: &Path) -> Self { path.to_path_buf().into() } } +impl From> for UrlBuf { + fn from(path: PathDyn) -> Self { + match path { + PathDyn::Os(p) => p.to_path_buf().into(), + } + } +} + impl FromStr for UrlBuf { type Err = anyhow::Error; @@ -81,12 +89,8 @@ impl PartialEq> for &UrlBuf { impl UrlBuf { #[inline] pub fn new() -> &'static Self { - static U: OnceLock = OnceLock::new(); - U.get_or_init(Self::default) - - // FIXME: use `LocBuf::empty()` when Rust 1.91.0 released - // static U: UrlBuf = UrlBuf { loc: LocBuf::empty(), scheme: Scheme::Regular - // }; &U + static U: UrlBuf = UrlBuf { loc: LocBuf::empty(), scheme: Scheme::Regular }; + &U } #[inline] @@ -104,6 +108,9 @@ impl UrlBuf { } impl UrlBuf { + #[inline] + pub fn loc(&self) -> Loc<'_> { self.loc.as_loc() } + // --- Regular #[inline] pub fn is_regular(&self) -> bool { self.as_url().is_regular() } diff --git a/yazi-shared/src/url/traits.rs b/yazi-shared/src/url/traits.rs index a05e6e48..49fc2950 100644 --- a/yazi-shared/src/url/traits.rs +++ b/yazi-shared/src/url/traits.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, ffi::OsStr, path::{Path, PathBuf}}; -use crate::{loc::Loc, path::PathDyn, scheme::{AsScheme, SchemeRef}, url::{Components, Display, Url, UrlBuf, UrlCow}}; +use crate::{loc::Loc, path::{AsPathDyn, PathDyn}, scheme::{AsScheme, SchemeRef}, url::{Components, Display, Url, UrlBuf, UrlCow}}; // --- AsUrl pub trait AsUrl { @@ -27,6 +27,15 @@ impl AsUrl for &PathBuf { fn as_url(&self) -> Url<'_> { (*self).as_path().as_url() } } +impl AsUrl for PathDyn<'_> { + #[inline] + fn as_url(&self) -> Url<'_> { + match *self { + Self::Os(p) => p.as_url(), + } + } +} + impl AsUrl for Url<'_> { #[inline] fn as_url(&self) -> Url<'_> { *self } @@ -101,13 +110,13 @@ where fn is_absolute(&self) -> bool { self.as_url().is_absolute() } - fn join(&self, path: impl AsRef) -> UrlBuf { self.as_url().join(path) } + fn join(&self, path: impl AsPathDyn) -> UrlBuf { self.as_url().join(path) } fn name(&self) -> Option<&OsStr> { self.as_url().name() } fn os_str(&self) -> Cow<'_, OsStr> { self.components().os_str() } - fn pair(&self) -> Option<(Url<'_>, &Path)> { self.as_url().pair() } + fn pair(&self) -> Option<(Url<'_>, PathDyn<'_>)> { self.as_url().pair() } fn parent(&self) -> Option> { self.as_url().parent() } @@ -115,11 +124,13 @@ where fn stem(&self) -> Option<&OsStr> { self.as_url().stem() } - fn strip_prefix(&self, base: impl AsUrl) -> Option<&Path> { self.as_url().strip_prefix(base) } + fn strip_prefix(&self, base: impl AsUrl) -> Option> { + self.as_url().strip_prefix(base) + } fn uri(&self) -> PathDyn<'_> { self.as_url().uri() } - fn urn(&self) -> &Path { self.as_url().urn() } + fn urn(&self) -> PathDyn<'_> { self.as_url().urn() } } impl UrlLike for UrlBuf {} diff --git a/yazi-shared/src/url/url.rs b/yazi-shared/src/url/url.rs index 1747528b..9c3e38a9 100644 --- a/yazi-shared/src/url/url.rs +++ b/yazi-shared/src/url/url.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::{Path, PathBuf use hashbrown::Equivalent; -use crate::{loc::{Loc, LocBuf}, path::{PathDyn, PathLike}, scheme::SchemeRef, url::{AsUrl, Components, Encode, UrlBuf}}; +use crate::{loc::{Loc, LocBuf}, path::{AsPathDyn, PathDyn, PathLike}, scheme::SchemeRef, url::{AsUrl, Components, Encode, UrlBuf}}; #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub struct Url<'a> { @@ -64,28 +64,30 @@ impl<'a> Url<'a> { #[inline] pub fn to_owned(self) -> UrlBuf { self.into() } - pub fn join(self, path: impl AsRef) -> UrlBuf { + pub fn join(self, path: impl AsPathDyn) -> UrlBuf { use SchemeRef as S; - let join = self.loc.join(path); + let joined = match path.as_path_dyn() { + PathDyn::Os(p) => self.loc.join(p), + }; let loc = match self.scheme { - S::Regular => join.into(), - S::Search(_) => LocBuf::::new(join, self.loc.base(), self.loc.base()), - S::Archive(_) => LocBuf::::floated(join, self.loc.base()), - S::Sftp(_) => join.into(), + S::Regular => joined.into(), + S::Search(_) => LocBuf::::new(joined, self.loc.base(), self.loc.base()), + S::Archive(_) => LocBuf::::floated(joined, self.loc.base()), + S::Sftp(_) => joined.into(), }; UrlBuf { loc, scheme: self.scheme.into() } } - pub fn strip_prefix(self, base: impl AsUrl) -> Option<&'a Path> { + pub fn strip_prefix(self, base: impl AsUrl) -> Option> { use SchemeRef as S; let base = base.as_url(); - let prefix = self.loc.strip_prefix(base.loc)?; + let prefix = self.loc.strip_prefix(base.loc)?.into(); - Some(match (self.scheme, base.scheme) { + match (self.scheme, base.scheme) { // Same scheme (S::Regular, S::Regular) => Some(prefix), (S::Search(_), S::Search(_)) => Some(prefix), @@ -109,14 +111,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) -> PathDyn<'a> { self.loc.uri().into() } #[inline] - pub fn urn(self) -> &'a Path { self.loc.urn() } + pub fn urn(self) -> PathDyn<'a> { self.loc.urn().into() } #[inline] pub fn name(self) -> Option<&'a OsStr> { self.loc.name() } @@ -200,7 +202,7 @@ impl<'a> Url<'a> { } #[inline] - pub fn pair(self) -> Option<(Self, &'a Path)> { Some((self.parent()?, self.loc.urn())) } + pub fn pair(self) -> Option<(Self, PathDyn<'a>)> { Some((self.parent()?, self.loc.urn().into())) } #[inline] pub fn as_path(self) -> Option<&'a Path> { diff --git a/yazi-vfs/src/op.rs b/yazi-vfs/src/op.rs index 32634a6b..68a7783c 100644 --- a/yazi-vfs/src/op.rs +++ b/yazi-vfs/src/op.rs @@ -1,5 +1,5 @@ use yazi_fs::FilesOp; -use yazi_shared::url::{UrlBuf, UrlLike}; +use yazi_shared::{path::PathLike, url::{UrlBuf, UrlLike}}; use crate::maybe_exists; @@ -15,7 +15,7 @@ impl VfsFilesOp for FilesOp { } else if maybe_exists(cwd).await { Self::IOErr(cwd.clone(), err).emit(); } else if let Some((p, n)) = cwd.pair() { - Self::Deleting(p.into(), [n.to_owned()].into()).emit(); + Self::Deleting(p.into(), [n.owned()].into()).emit(); } } } diff --git a/yazi-watcher/src/local/local.rs b/yazi-watcher/src/local/local.rs index 90de2cf2..fd6725e4 100644 --- a/yazi-watcher/src/local/local.rs +++ b/yazi-watcher/src/local/local.rs @@ -7,7 +7,7 @@ use tokio::{pin, sync::mpsc::{self, UnboundedReceiver}}; use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use tracing::error; use yazi_fs::{File, FilesOp, provider}; -use yazi_shared::url::{UrlBuf, UrlLike}; +use yazi_shared::{path::PathLike, url::{UrlBuf, UrlLike}}; use yazi_vfs::VfsFile; use crate::{Reporter, WATCHER}; @@ -70,18 +70,18 @@ impl Local { for u in urls { let Some((parent, urn)) = u.pair() else { continue }; let Ok(file) = File::new(&u).await else { - ops.push(FilesOp::Deleting(parent.into(), [urn.to_owned()].into())); + ops.push(FilesOp::Deleting(parent.into(), [urn.owned()].into())); continue; }; if let Some(p) = file.url.as_path() && !provider::local::must_case_match(p).await { - ops.push(FilesOp::Deleting(parent.into(), [urn.to_owned()].into())); + ops.push(FilesOp::Deleting(parent.into(), [urn.owned()].into())); continue; } - ops.push(FilesOp::Upserting(parent.into(), [(urn.to_owned(), file)].into())); + ops.push(FilesOp::Upserting(parent.into(), [(urn.owned(), file)].into())); } FilesOp::mutate(ops); diff --git a/yazi-watcher/src/remote/remote.rs b/yazi-watcher/src/remote/remote.rs index cd29029c..55269834 100644 --- a/yazi-watcher/src/remote/remote.rs +++ b/yazi-watcher/src/remote/remote.rs @@ -6,7 +6,7 @@ use tokio::{pin, sync::mpsc::UnboundedReceiver}; use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use yazi_fs::{File, FilesOp}; use yazi_proxy::MgrProxy; -use yazi_shared::url::{Url, UrlBuf, UrlLike}; +use yazi_shared::{path::PathLike, url::{Url, UrlBuf, UrlLike}}; use yazi_vfs::VfsFile; use crate::{Reporter, WATCHER}; @@ -39,14 +39,14 @@ impl Remote { for u in urls { let Some((parent, urn)) = u.pair() else { continue }; let Ok(mut file) = File::new(&u).await else { - ops.push(FilesOp::Deleting(parent.into(), [urn.to_owned()].into())); + ops.push(FilesOp::Deleting(parent.into(), [urn.owned()].into())); continue; }; let is_file = file.is_file(); file.cha.ctime = Some(SystemTime::now()); - ops.push(FilesOp::Upserting(parent.into(), [(urn.to_owned(), file)].into())); + ops.push(FilesOp::Upserting(parent.into(), [(urn.owned(), file)].into())); if is_file { ups.push(u); } diff --git a/yazi-watcher/src/reporter.rs b/yazi-watcher/src/reporter.rs index ef5d332f..a9a1776c 100644 --- a/yazi-watcher/src/reporter.rs +++ b/yazi-watcher/src/reporter.rs @@ -1,5 +1,5 @@ use tokio::sync::mpsc; -use yazi_shared::{scheme::SchemeRef, url::{AsUrl, Url, UrlBuf, UrlCow, UrlLike}}; +use yazi_shared::{path::PathLike, scheme::SchemeRef, url::{AsUrl, Url, UrlBuf, UrlCow, UrlLike}}; use crate::{WATCHED, local::LINKED};