diff --git a/Cargo.toml b/Cargo.toml index d9e4b1e8..3b04c220 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,8 +59,11 @@ unicode-width = { version = "0.2.0", default-features = false } uzers = "0.12.1" [workspace.lints.clippy] -format_push_string = "warn" -implicit_clone = "warn" -module_inception = "allow" -unit_arg = "allow" -use_self = "warn" +format_push_string = "warn" +if_same_then_else = "allow" +implicit_clone = "warn" +len_without_is_empty = "allow" +missing_safety_doc = "allow" +module_inception = "allow" +unit_arg = "allow" +use_self = "warn" diff --git a/yazi-actor/src/cmp/show.rs b/yazi-actor/src/cmp/show.rs index 3e151c1c..b747baba 100644 --- a/yazi-actor/src/cmp/show.rs +++ b/yazi-actor/src/cmp/show.rs @@ -3,7 +3,7 @@ use std::{mem, ops::ControlFlow}; use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::cmp::{CmpItem, ShowOpt}; -use yazi_shared::{data::Data, path::{AsPathDyn, PathDyn, PathLike}, strand::{AsStrand, StrandLike}}; +use yazi_shared::{data::Data, path::{AsPath, PathDyn}, strand::StrandLike}; use crate::{Actor, Ctx}; @@ -30,7 +30,7 @@ impl Actor for Show { }; cmp.ticket = opt.ticket; - cmp.cands = Self::match_candidates(opt.word.as_path_dyn(), cache); + cmp.cands = Self::match_candidates(opt.word.as_path(), cache); if cmp.cands.is_empty() { succ!(render!(mem::replace(&mut cmp.visible, false))); } @@ -47,16 +47,15 @@ impl Show { let smart = !word.encoded_bytes().iter().any(|&b| b.is_ascii_uppercase()); let flow = cache.iter().try_fold((Vec::new(), Vec::new()), |(mut exact, mut fuzzy), item| { - let name = item.name.as_strand(); let starts_with = - if smart { name.eq_ignore_ascii_case(word) } else { name.starts_with(word) }; + if smart { item.name.eq_ignore_ascii_case(word) } else { item.name.starts_with(word) }; if starts_with { exact.push(item); if exact.len() >= LIMIT { return ControlFlow::Break((exact, fuzzy)); } - } else if fuzzy.len() < LIMIT - exact.len() && name.contains(word) { + } else if fuzzy.len() < LIMIT - exact.len() && item.name.contains(word) { // Here we don't break the control flow, since we want more exact matching. fuzzy.push(item) } diff --git a/yazi-actor/src/cmp/trigger.rs b/yazi-actor/src/cmp/trigger.rs index 3cc13427..c092099f 100644 --- a/yazi-actor/src/cmp/trigger.rs +++ b/yazi-actor/src/cmp/trigger.rs @@ -5,7 +5,7 @@ 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::{AnyAsciiChar, data::Data, natsort, path::{AsPath, PathBufDyn, PathLike}, scheme::{SchemeCow, SchemeLike}, strand::StrandBufLike, url::{UrlBuf, UrlCow, UrlLike}}; +use yazi_shared::{AnyAsciiChar, data::Data, natsort, path::{PathBufDyn, PathDyn, PathLike}, scheme::{SchemeCow, SchemeLike}, strand::StrandLike, url::{UrlBuf, UrlCow, UrlLike}}; use yazi_vfs::provider; use crate::{Actor, Ctx}; @@ -74,20 +74,17 @@ impl Trigger { } let sep = if cfg!(windows) { - AnyAsciiChar::new(&[b'/', b'\\']).unwrap() + AnyAsciiChar::new(b"/\\").unwrap() } else { - AnyAsciiChar::new(&[b'/']).unwrap() + AnyAsciiChar::new(b"/").unwrap() }; - Some(match path.as_path().rsplit_pred(sep) { + Some(match path.rsplit_pred(sep) { Some((p, c)) if p.is_empty() => { - let root = PathBufDyn::with(scheme.kind(), MAIN_SEPARATOR_STR).expect("valid root"); + let root = PathDyn::with(scheme.kind(), MAIN_SEPARATOR_STR).expect("valid root"); (UrlCow::try_from((scheme, root)).ok()?.into_owned(), c.into()) } - Some((p, c)) => { - let parent = PathBufDyn::with(scheme.kind(), p.as_dyn()).expect("valid parent"); - (expand_url(UrlCow::try_from((scheme, parent)).ok()?), c.into()) - } + Some((p, c)) => (expand_url(UrlCow::try_from((scheme, p)).ok()?), c.into()), None => (CWD.load().as_ref().clone(), path.into()), }) } @@ -95,7 +92,7 @@ impl Trigger { #[cfg(test)] mod tests { - use yazi_shared::{path::PathBufLike, url::UrlLike}; + use yazi_shared::url::UrlLike; use super::*; @@ -113,11 +110,19 @@ mod tests { yazi_fs::init(); compare("", "", ""); compare(" ", "", " "); + compare("/", "/", ""); - compare("//", "//", ""); + compare("//", "/", ""); + compare("///", "/", ""); + compare("/foo", "/", "foo"); + compare("//foo", "/", "foo"); + compare("///foo", "/", "foo"); + compare("/foo/", "/foo/", ""); + compare("//foo/", "/foo/", ""); compare("/foo/bar", "/foo/", "bar"); + compare("///foo/bar", "/foo/", "bar"); } #[cfg(windows)] diff --git a/yazi-actor/src/lives/file.rs b/yazi-actor/src/lives/file.rs index fc6aa3b7..ac978929 100644 --- a/yazi-actor/src/lives/file.rs +++ b/yazi-actor/src/lives/file.rs @@ -4,7 +4,7 @@ use mlua::{AnyUserData, IntoLua, UserData, UserDataFields, UserDataMethods, Valu use yazi_binding::Style; use yazi_config::THEME; use yazi_plugin::bindings::Range; -use yazi_shared::{path::PathLike, url::UrlLike}; +use yazi_shared::url::UrlLike; use super::Lives; use crate::lives::PtrCell; diff --git a/yazi-actor/src/lives/tab.rs b/yazi-actor/src/lives/tab.rs index 311af5b9..1c4ab5dd 100644 --- a/yazi-actor/src/lives/tab.rs +++ b/yazi-actor/src/lives/tab.rs @@ -2,7 +2,7 @@ use std::ops::Deref; use mlua::{AnyUserData, UserData, UserDataFields, UserDataMethods, Value}; use yazi_binding::{Id, UrlRef, cached_field}; -use yazi_shared::{path::PathLike, strand::StrandLike, url::UrlLike}; +use yazi_shared::url::UrlLike; use super::{Finder, Folder, Lives, Mode, Preference, Preview, PtrCell, Selected}; diff --git a/yazi-actor/src/mgr/cd.rs b/yazi-actor/src/mgr/cd.rs index 3ed6b1ec..73003575 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, path::PathLike, url::{AsUrl, UrlBuf, UrlLike}}; +use yazi_shared::{Debounce, data::Data, errors::InputError, 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().owned(), file)].into()).emit(); + FilesOp::Upserting(p.into(), [(url.urn().into(), file)].into()).emit(); } MgrProxy::reveal(&url); } diff --git a/yazi-actor/src/mgr/create.rs b/yazi-actor/src/mgr/create.rs index 733617f1..05e278a9 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, path::PathLike, url::{UrlBuf, UrlLike}}; +use yazi_shared::{data::Data, url::{UrlBuf, UrlLike}}; use yazi_vfs::{VfsFile, maybe_exists, provider}; use yazi_watcher::WATCHER; @@ -54,7 +54,7 @@ impl Create { && let Some((parent, urn)) = real.pair() { ok_or_not_found!(provider::remove_file(&new).await); - FilesOp::Deleting(parent.into(), [urn.owned()].into()).emit(); + FilesOp::Deleting(parent.into(), [urn.into()].into()).emit(); provider::create(&new).await?; } else if let Some(parent) = new.parent() { provider::create_dir_all(parent).await.ok(); @@ -68,7 +68,7 @@ impl Create { && let Some((parent, urn)) = real.pair() { let file = File::new(&real).await?; - FilesOp::Upserting(parent.into(), [(urn.owned(), file)].into()).emit(); + FilesOp::Upserting(parent.into(), [(urn.into(), 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 6998907b..37062d6c 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, path::PathLike}; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; @@ -16,7 +16,7 @@ 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().owned()); + let hovered = cx.hovered().map(|f| f.urn().into()); cx.current_mut().files.set_filter(filter); if cx.hovered().map(|f| f.urn()) != hovered.as_ref().map(Into::into) { diff --git a/yazi-actor/src/mgr/hidden.rs b/yazi-actor/src/mgr/hidden.rs index 2aba7f2b..1e42ee7d 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, path::PathLike}; +use yazi_shared::data::Data; 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().owned()); + let hovered = cx.hovered().map(|f| f.urn().to_owned()); let apply = |f: &mut Folder| { if f.stage == FolderStage::Loading { render!(); diff --git a/yazi-actor/src/mgr/rename.rs b/yazi-actor/src/mgr/rename.rs index ef60c7a2..0c857d73 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, path::PathLike, strand::StrandLike, url::{UrlBuf, UrlLike}}; +use yazi_shared::{Id, data::Data, url::{UrlBuf, UrlLike}}; use yazi_vfs::{VfsFile, maybe_exists, provider}; use yazi_watcher::WATCHER; @@ -73,10 +73,11 @@ impl Rename { provider::rename(&old, &new).await?; if let Ok(u) = overwritten + && u != new && let Some((parent, urn)) = u.pair() { ok_or_not_found!(provider::rename(&u, &new).await); - FilesOp::Deleting(parent.to_owned(), [urn.owned()].into()).emit(); + FilesOp::Deleting(parent.to_owned(), [urn.into()].into()).emit(); } let new = provider::casefold(&new).await?; @@ -84,10 +85,10 @@ impl Rename { let file = File::new(&new).await?; if new_p == old_p { - FilesOp::Upserting(old_p.into(), [(old_n.owned(), file)].into()).emit(); + FilesOp::Upserting(old_p.into(), [(old_n.into(), file)].into()).emit(); } else { - FilesOp::Deleting(old_p.into(), [old_n.owned()].into()).emit(); - FilesOp::Upserting(new_p.into(), [(new_n.owned(), file)].into()).emit(); + FilesOp::Deleting(old_p.into(), [old_n.into()].into()).emit(); + FilesOp::Upserting(new_p.into(), [(new_n.into(), file)].into()).emit(); } MgrProxy::reveal(&new); diff --git a/yazi-actor/src/mgr/reveal.rs b/yazi-actor/src/mgr/reveal.rs index d174d10f..590d0924 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, path::PathLike, url::UrlLike}; +use yazi_shared::{data::Data, 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.owned()))?; + act!(mgr:hover, cx, Some(child.into()))?; 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 d29a2efd..d36604d0 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, path::PathLike}; +use yazi_shared::data::Data; 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().owned()); + let hovered = cx.hovered().map(|f| f.urn().to_owned()); let apply = |f: &mut Folder| { if f.stage == FolderStage::Loading { render!(); diff --git a/yazi-actor/src/mgr/update_files.rs b/yazi-actor/src/mgr/update_files.rs index e2c1479e..af0cd4a5 100644 --- a/yazi-actor/src/mgr/update_files.rs +++ b/yazi-actor/src/mgr/update_files.rs @@ -17,8 +17,7 @@ impl Actor for UpdateFiles { fn act(cx: &mut Ctx, opt: Self::Options) -> Result { let revision = cx.current().files.revision; - let linked: Vec<_> = - LINKED.read().from_dir(opt.op.cwd()).filter_map(|u| opt.op.chdir(u).ok()).collect(); + let linked: Vec<_> = LINKED.read().from_dir(opt.op.cwd()).map(|u| opt.op.chdir(u)).collect(); for op in [opt.op].into_iter().chain(linked) { cx.mgr.yanked.apply_op(&op); diff --git a/yazi-binding/Cargo.toml b/yazi-binding/Cargo.toml index 0ed3286d..cd8077cd 100644 --- a/yazi-binding/Cargo.toml +++ b/yazi-binding/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi Lua bindings" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [features] default = [ "vendored-lua" ] vendored-lua = [ "mlua/vendored" ] diff --git a/yazi-binding/src/macros.rs b/yazi-binding/src/macros.rs index 7e5c69b4..9e0bbcb3 100644 --- a/yazi-binding/src/macros.rs +++ b/yazi-binding/src/macros.rs @@ -154,7 +154,6 @@ macro_rules! impl_file_fields { $crate::cached_field!($fields, link_to, |_, me| Ok(me.link_to_url().map($crate::Url::new))); $crate::cached_field!($fields, name, |lua, me| { - use yazi_shared::strand::StrandLike; me.name().map(|s| lua.create_string(s.encoded_bytes())).transpose() }); $crate::cached_field!($fields, cache, |_, me| { diff --git a/yazi-binding/src/path.rs b/yazi-binding/src/path.rs index edcce546..03288668 100644 --- a/yazi-binding/src/path.rs +++ b/yazi-binding/src/path.rs @@ -1,7 +1,7 @@ use std::ops::Deref; use mlua::{ExternalError, FromLua, Lua, MetaMethod, UserData, UserDataMethods, Value}; -use yazi_shared::path::{PathBufDyn, PathBufLike}; +use yazi_shared::path::{PathBufDyn, PathLike}; pub struct Path(pub PathBufDyn); diff --git a/yazi-binding/src/runtime.rs b/yazi-binding/src/runtime.rs index 2eec279b..db73b1c2 100644 --- a/yazi-binding/src/runtime.rs +++ b/yazi-binding/src/runtime.rs @@ -49,7 +49,7 @@ impl Runtime { if let Some(v) = self.blocks.get_mut(&cur.id) { v.push(f); } else { - self.blocks.insert(cur.id.to_owned(), vec![f]); + self.blocks.insert(cur.id.clone(), vec![f]); } true } diff --git a/yazi-binding/src/url.rs b/yazi-binding/src/url.rs index c86d34f2..7577d8b0 100644 --- a/yazi-binding/src/url.rs +++ b/yazi-binding/src/url.rs @@ -2,7 +2,7 @@ use std::ops::Deref; use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, Value}; use yazi_fs::{FsHash64, FsHash128}; -use yazi_shared::{path::{PathLike, StripPrefixError}, strand::{StrandCow, StrandLike}, url::{AsUrl, UrlCow, UrlLike}}; +use yazi_shared::{path::StripPrefixError, strand::StrandCow, url::{AsUrl, UrlCow, UrlLike}}; use crate::{Scheme, cached_field, deprecate}; diff --git a/yazi-config/Cargo.toml b/yazi-config/Cargo.toml index 382716fe..7736f0dc 100644 --- a/yazi-config/Cargo.toml +++ b/yazi-config/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi configuration file parser" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-codegen = { path = "../yazi-codegen", version = "25.9.15" } yazi-fs = { path = "../yazi-fs", version = "25.9.15" } diff --git a/yazi-config/src/mgr/mgr.rs b/yazi-config/src/mgr/mgr.rs index f18066c4..3f176ce7 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, path::PathLike, url::{UrlBuf, UrlLike}}; +use yazi_shared::{SyncCell, url::{UrlBuf, UrlLike}}; use super::{MgrRatio, MouseEvents}; diff --git a/yazi-config/src/pattern.rs b/yazi-config/src/pattern.rs index 72a52278..acb580ce 100644 --- a/yazi-config/src/pattern.rs +++ b/yazi-config/src/pattern.rs @@ -3,7 +3,7 @@ use std::{fmt::Debug, str::FromStr}; use anyhow::{Result, bail}; use globset::{Candidate, GlobBuilder}; use serde::Deserialize; -use yazi_shared::{path::PathLike, scheme::SchemeKind, url::AsUrl}; +use yazi_shared::{scheme::SchemeKind, url::AsUrl}; #[derive(Deserialize)] #[serde(try_from = "String")] @@ -28,7 +28,6 @@ impl Debug for Pattern { } impl Pattern { - // FIXME: simplify conditional compilation pub fn match_url(&self, url: impl AsUrl, is_dir: bool) -> bool { let url = url.as_url(); @@ -47,9 +46,9 @@ impl Pattern { #[cfg(windows)] if self.sep_lit { - use yazi_shared::strand::AsStrandDyn; + use yazi_shared::strand::{AsStrand, StrandLike}; self.inner.is_match_candidate(&Candidate::from_bytes( - url.loc().as_strand_dyn().backslash_to_slash().encoded_bytes(), + url.loc().as_strand().backslash_to_slash().encoded_bytes(), )) } else { self.inner.is_match_candidate(&Candidate::from_bytes(url.loc().encoded_bytes())) diff --git a/yazi-config/src/popup/options.rs b/yazi-config/src/popup/options.rs index 66b45b02..85fd42f7 100644 --- a/yazi-config/src/popup/options.rs +++ b/yazi-config/src/popup/options.rs @@ -33,7 +33,7 @@ pub struct ConfirmCfg { impl InputCfg { pub fn cd() -> Self { Self { - title: YAZI.input.cd_title.to_owned(), + title: YAZI.input.cd_title.clone(), position: Position::new(YAZI.input.cd_origin, YAZI.input.cd_offset), completion: true, ..Default::default() @@ -42,7 +42,7 @@ impl InputCfg { pub fn create(dir: bool) -> Self { Self { - title: YAZI.input.create_title[dir as usize].to_owned(), + title: YAZI.input.create_title[dir as usize].clone(), position: Position::new(YAZI.input.create_origin, YAZI.input.create_offset), ..Default::default() } @@ -50,7 +50,7 @@ impl InputCfg { pub fn rename() -> Self { Self { - title: YAZI.input.rename_title.to_owned(), + title: YAZI.input.rename_title.clone(), position: Position::new(YAZI.input.rename_origin, YAZI.input.rename_offset), ..Default::default() } @@ -58,7 +58,7 @@ impl InputCfg { pub fn filter() -> Self { Self { - title: YAZI.input.filter_title.to_owned(), + title: YAZI.input.filter_title.clone(), position: Position::new(YAZI.input.filter_origin, YAZI.input.filter_offset), realtime: true, ..Default::default() @@ -67,7 +67,7 @@ impl InputCfg { pub fn find(prev: bool) -> Self { Self { - title: YAZI.input.find_title[prev as usize].to_owned(), + title: YAZI.input.find_title[prev as usize].clone(), position: Position::new(YAZI.input.find_origin, YAZI.input.find_offset), realtime: true, ..Default::default() @@ -84,7 +84,7 @@ impl InputCfg { pub fn shell(block: bool) -> Self { Self { - title: YAZI.input.shell_title[block as usize].to_owned(), + title: YAZI.input.shell_title[block as usize].clone(), position: Position::new(YAZI.input.shell_origin, YAZI.input.shell_offset), ..Default::default() } @@ -138,7 +138,7 @@ impl ConfirmCfg { pub fn overwrite(url: &UrlBuf) -> Self { Self::new( - YAZI.confirm.overwrite_title.to_owned(), + YAZI.confirm.overwrite_title.clone(), YAZI.confirm.overwrite_position(), Some(Text::raw(&YAZI.confirm.overwrite_body)), Some(url.into_string_lossy().into()), @@ -183,7 +183,7 @@ impl PickCfg { pub fn open(items: Vec) -> Self { let max_height = Self::max_height(items.len()); Self { - title: YAZI.pick.open_title.to_owned(), + title: YAZI.pick.open_title.clone(), items, position: Position::new(YAZI.pick.open_origin, Offset { height: max_height, diff --git a/yazi-config/src/theme/icon.rs b/yazi-config/src/theme/icon.rs index 98d2c01e..d8f0dc38 100644 --- a/yazi-config/src/theme/icon.rs +++ b/yazi-config/src/theme/icon.rs @@ -5,7 +5,7 @@ use hashbrown::HashMap; use serde::{Deserialize, Deserializer}; use yazi_codegen::DeserializeOver2; use yazi_fs::File; -use yazi_shared::{Condition, strand::StrandLike, url::UrlLike}; +use yazi_shared::{Condition, url::UrlLike}; use crate::{Color, Icon as I, Pattern, Style}; diff --git a/yazi-core/Cargo.toml b/yazi-core/Cargo.toml index 0a0106a8..4a12ce0e 100644 --- a/yazi-core/Cargo.toml +++ b/yazi-core/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi core logic" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-adapter = { path = "../yazi-adapter", version = "25.9.15" } yazi-config = { path = "../yazi-config", version = "25.9.15" } diff --git a/yazi-core/src/tab/finder.rs b/yazi-core/src/tab/finder.rs index 4ba100f7..506eb86e 100644 --- a/yazi-core/src/tab/finder.rs +++ b/yazi-core/src/tab/finder.rs @@ -1,7 +1,7 @@ use anyhow::Result; use hashbrown::HashMap; use yazi_fs::{Files, Filter, FilterCase}; -use yazi_shared::{path::{AsPathDyn, PathBufDyn, PathLike}, url::UrlBuf}; +use yazi_shared::{path::{AsPath, PathBufDyn}, url::UrlBuf}; use crate::tab::Folder; @@ -62,7 +62,7 @@ impl Finder { continue; } - self.matched.insert(file.urn().owned(), i); + self.matched.insert(file.urn().into(), i); if self.matched.len() > 99 { break; } @@ -78,9 +78,9 @@ impl Finder { impl Finder { pub fn matched_idx(&self, folder: &Folder, urn: T) -> Option where - T: AsPathDyn, + T: AsPath, { - if self.lock == *folder { self.matched.get(&urn.as_path_dyn()).copied() } else { None } + if self.lock == *folder { self.matched.get(&urn.as_path()).copied() } else { None } } } diff --git a/yazi-core/src/tab/folder.rs b/yazi-core/src/tab/folder.rs index 51eabad5..41da80b7 100644 --- a/yazi-core/src/tab/folder.rs +++ b/yazi-core/src/tab/folder.rs @@ -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, path::{PathBufDyn, PathBufLike, PathDyn, PathLike}, url::UrlBuf}; +use yazi_shared::{Id, path::{AsPath, PathBufDyn, PathDyn}, url::UrlBuf}; use yazi_widgets::Scrollable; pub struct Folder { @@ -101,7 +101,7 @@ impl Folder { self.scroll(step) }; - self.trace = self.hovered().filter(|_| b).map(|h| h.urn().owned()).or(self.trace.take()); + self.trace = self.hovered().filter(|_| b).map(|h| h.urn().into()).or(self.trace.take()); b |= self.squeeze_offset(); self.sync_page(false); @@ -121,7 +121,7 @@ impl Folder { if let Some(u) = urn { self.hover(u) } else if let Some(u) = &self.trace { - self.hover(u.clone().borrow()) + self.hover(u.clone().as_path()) } else { self.arrow(0) } diff --git a/yazi-core/src/tab/preference.rs b/yazi-core/src/tab/preference.rs index c6ebf35e..275cd40c 100644 --- a/yazi-core/src/tab/preference.rs +++ b/yazi-core/src/tab/preference.rs @@ -26,7 +26,7 @@ impl Default for Preference { sort_translit: YAZI.mgr.sort_translit.get(), // Display - linemode: YAZI.mgr.linemode.to_owned(), + linemode: YAZI.mgr.linemode.clone(), show_hidden: YAZI.mgr.show_hidden.get(), } } diff --git a/yazi-dds/Cargo.toml b/yazi-dds/Cargo.toml index 4bff6675..59ac2629 100644 --- a/yazi-dds/Cargo.toml +++ b/yazi-dds/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi data distribution service" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [features] default = [ "vendored-lua" ] vendored-lua = [ "mlua/vendored" ] diff --git a/yazi-ffi/Cargo.toml b/yazi-ffi/Cargo.toml index 32fe61b3..40ae271e 100644 --- a/yazi-ffi/Cargo.toml +++ b/yazi-ffi/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi foreign function interface" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-macro = { path = "../yazi-macro", version = "25.9.15" } diff --git a/yazi-fm/Cargo.toml b/yazi-fm/Cargo.toml index 9feaccbb..177a063b 100644 --- a/yazi-fm/Cargo.toml +++ b/yazi-fm/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi file manager" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [profile.release] codegen-units = 1 lto = true diff --git a/yazi-fm/src/app/commands/bootstrap.rs b/yazi-fm/src/app/commands/bootstrap.rs index af83c5b2..bb3e3bbb 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, strand::StrandBufLike, url::UrlLike}; +use yazi_shared::{data::Data, strand::StrandLike, url::UrlLike}; use crate::app::App; diff --git a/yazi-fm/src/cmp/cmp.rs b/yazi-fm/src/cmp/cmp.rs index f06fb1c0..9a7376df 100644 --- a/yazi-fm/src/cmp/cmp.rs +++ b/yazi-fm/src/cmp/cmp.rs @@ -4,7 +4,7 @@ use ratatui::{buffer::Buffer, layout::Rect, widgets::{Block, BorderType, List, L use yazi_adapter::Dimension; use yazi_config::{THEME, popup::{Offset, Position}}; use yazi_core::Core; -use yazi_shared::strand::{AsStrand, StrandLike}; +use yazi_shared::strand::StrandLike; pub(crate) struct Cmp<'a> { core: &'a Core, @@ -26,7 +26,7 @@ impl Widget for Cmp<'_> { let icon = if x.is_dir { &THEME.cmp.icon_folder } else { &THEME.cmp.icon_file }; let slash = if x.is_dir { MAIN_SEPARATOR_STR } else { "" }; - let mut item = ListItem::new(format!(" {icon} {}{slash}", x.name.as_strand().display())); + let mut item = ListItem::new(format!(" {icon} {}{slash}", x.name.display())); if i == self.core.cmp.rel_cursor() { item = item.style(THEME.cmp.active); } else { diff --git a/yazi-fs/Cargo.toml b/yazi-fs/Cargo.toml index edd1e4d7..deba1893 100644 --- a/yazi-fs/Cargo.toml +++ b/yazi-fs/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi file system" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-ffi = { path = "../yazi-ffi", version = "25.9.15" } yazi-macro = { path = "../yazi-macro", version = "25.9.15" } diff --git a/yazi-fs/src/cha/cha.rs b/yazi-fs/src/cha/cha.rs index f64003e7..f8ebb49d 100644 --- a/yazi-fs/src/cha/cha.rs +++ b/yazi-fs/src/cha/cha.rs @@ -62,8 +62,6 @@ 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; diff --git a/yazi-fs/src/cha/kind.rs b/yazi-fs/src/cha/kind.rs index 4e2736f9..7a20ce58 100644 --- a/yazi-fs/src/cha/kind.rs +++ b/yazi-fs/src/cha/kind.rs @@ -23,7 +23,6 @@ impl ChaKind { #[cfg(unix)] { - use yazi_shared::strand::StrandLike; if _name.as_strand().starts_with(".") { me |= Self::HIDDEN; } diff --git a/yazi-fs/src/cha/mode.rs b/yazi-fs/src/cha/mode.rs index 0961d1d1..fc498bfb 100644 --- a/yazi-fs/src/cha/mode.rs +++ b/yazi-fs/src/cha/mode.rs @@ -80,7 +80,7 @@ impl From for std::fs::Permissions { fn from(value: ChaMode) -> Self { use std::os::unix::fs::PermissionsExt; - std::fs::Permissions::from_mode(value.bits() as _) + Self::from_mode(value.bits() as _) } } diff --git a/yazi-fs/src/error/serde.rs b/yazi-fs/src/error/serde.rs index 06ee5779..a5b9a289 100644 --- a/yazi-fs/src/error/serde.rs +++ b/yazi-fs/src/error/serde.rs @@ -114,9 +114,9 @@ impl Serialize for Error { } match self { - Error::Kind(kind) => Shadow::Kind { kind: kind_to_str(*kind) }.serialize(serializer), - Error::Raw(code) => Shadow::Raw { code: *code }.serialize(serializer), - Error::Custom { kind, code, message } => { + Self::Kind(kind) => Shadow::Kind { kind: kind_to_str(*kind) }.serialize(serializer), + Self::Raw(code) => Shadow::Raw { code: *code }.serialize(serializer), + Self::Custom { kind, code, message } => { Shadow::Dyn { kind: kind_to_str(*kind), code: *code, message }.serialize(serializer) } } @@ -138,15 +138,15 @@ impl<'de> Deserialize<'de> for Error { let shadow = Shadow::deserialize(deserializer)?; Ok(match shadow { - Shadow::Kind { kind } => Error::Kind(kind_from_str(&kind)), - Shadow::Raw { code } => Error::Raw(code), + Shadow::Kind { kind } => Self::Kind(kind_from_str(&kind)), + Shadow::Raw { code } => Self::Raw(code), Shadow::Dyn { kind, code, message } => { if !message.is_empty() { - Error::Custom { kind: kind_from_str(&kind), code, message: message.into() } + Self::Custom { kind: kind_from_str(&kind), code, message: message.into() } } else if let Some(code) = code { - Error::Raw(code) + Self::Raw(code) } else { - Error::Kind(kind_from_str(&kind)) + Self::Kind(kind_from_str(&kind)) } } }) diff --git a/yazi-fs/src/file.rs b/yazi-fs/src/file.rs index 7e3414c3..17d46159 100644 --- a/yazi-fs/src/file.rs +++ b/yazi-fs/src/file.rs @@ -1,7 +1,6 @@ use std::{hash::{Hash, Hasher}, ops::Deref, path::Path}; -use anyhow::Result; -use yazi_shared::{loc::Loc, path::{AsPathDyn, PathBufDyn, PathDyn}, strand::Strand, url::{Url, UrlBuf, UrlLike}}; +use yazi_shared::{loc::Loc, path::{PathBufDyn, PathDyn, PathLike}, strand::Strand, url::{Url, UrlBuf, UrlLike}}; use crate::cha::{Cha, ChaType}; @@ -27,15 +26,15 @@ impl File { } #[inline] - pub fn chdir(&self, wd: &Path) -> Result { - Ok(Self { url: self.url.rebase(wd)?, cha: self.cha, link_to: self.link_to.clone() }) + pub fn chdir(&self, wd: &Path) -> Self { + Self { url: self.url.rebase(wd), cha: self.cha, link_to: self.link_to.clone() } } } impl File { // --- Url #[inline] - pub fn url_owned(&self) -> UrlBuf { self.url.to_owned() } + pub fn url_owned(&self) -> UrlBuf { self.url.clone() } #[inline] pub fn uri(&self) -> PathDyn<'_> { self.url.uri() } @@ -50,7 +49,7 @@ impl File { pub fn stem(&self) -> Option> { self.url.stem() } pub fn link_to_url(&self) -> Option> { - let to = self.link_to.as_ref()?.as_path_dyn(); + let to = self.link_to.as_ref()?; let kind = self.url.kind(); Some(match &self.url { UrlBuf::Regular(_) => Url::Regular(Loc::bare(to.as_os().ok()?)), diff --git a/yazi-fs/src/files.rs b/yazi-fs/src/files.rs index 937e9e9a..da21656e 100644 --- a/yazi-fs/src/files.rs +++ b/yazi-fs/src/files.rs @@ -1,7 +1,7 @@ use std::{mem, ops::{Deref, DerefMut, Not}}; use hashbrown::{HashMap, HashSet}; -use yazi_shared::{Id, path::{PathBufDyn, PathDyn, PathLike}}; +use yazi_shared::{Id, path::{PathBufDyn, PathDyn}}; use super::{FilesSorter, Filter}; use crate::{FILES_TICKET, File, SortBy}; @@ -97,7 +97,7 @@ impl Files { macro_rules! go { ($dist:expr, $src:expr, $inc:literal) => { - let mut todo: HashMap<_, _> = $src.into_iter().map(|f| (f.urn().owned(), f)).collect(); + let mut todo: HashMap<_, _> = $src.into_iter().map(|f| (f.urn().to_owned(), f)).collect(); for f in &$dist { if todo.remove(&f.urn()).is_some() && todo.is_empty() { break; @@ -121,19 +121,17 @@ impl Files { #[cfg(unix)] pub fn update_deleting(&mut self, urns: HashSet) -> Vec { - use yazi_shared::path::PathBufLike; + 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.borrow().is_hidden()) || !filter.matches(u)) + 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.borrow().is_hidden()) + urns.into_iter().partition(|u| u.is_hidden()) }; let mut deleted = Vec::with_capacity(items.len()); @@ -229,7 +227,7 @@ impl Files { } self.update_deleting( - files.iter().filter(|&(u, f)| u != f.urn()).map(|(_, f)| f.urn().owned()).collect(), + files.iter().filter(|&(u, f)| u != f.urn()).map(|(_, f)| f.urn().into()).collect(), ); let (hidden, items) = self.update_updating(files); diff --git a/yazi-fs/src/filter.rs b/yazi-fs/src/filter.rs index 8bed557d..7baf323c 100644 --- a/yazi-fs/src/filter.rs +++ b/yazi-fs/src/filter.rs @@ -2,7 +2,7 @@ use std::{fmt::Display, ops::Range}; use anyhow::Result; use regex::bytes::{Regex, RegexBuilder}; -use yazi_shared::{event::Cmd, strand::{AsStrand, StrandLike}}; +use yazi_shared::{event::Cmd, strand::AsStrand}; pub struct Filter { raw: String, diff --git a/yazi-fs/src/op.rs b/yazi-fs/src/op.rs index f6d111bd..3e8fe3bf 100644 --- a/yazi-fs/src/op.rs +++ b/yazi-fs/src/op.rs @@ -1,9 +1,8 @@ use std::path::Path; -use anyhow::Result; use hashbrown::{HashMap, HashSet}; use yazi_macro::relay; -use yazi_shared::{Id, Ids, path::{PathBufDyn, PathLike}, url::{UrlBuf, UrlLike}}; +use yazi_shared::{Id, Ids, path::PathBufDyn, url::{UrlBuf, UrlLike}}; use super::File; use crate::{cha::Cha, error::Error}; @@ -58,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().owned(), n); + parents.entry_ref(&o_p).or_default().1.insert(o.urn().into(), n); } else { - 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); + parents.entry_ref(&o_p).or_default().0.insert(o.urn().into()); + parents.entry_ref(&n_p).or_default().1.insert(n.urn().into(), n); } } for (p, (o, n)) in parents { @@ -99,21 +98,16 @@ impl FilesOp { } } - pub fn chdir(&self, wd: &Path) -> Result { + pub fn chdir(&self, wd: &Path) -> Self { macro_rules! files { - ($files:expr) => {{ $files.iter().map(|file| file.chdir(wd)).collect::>()? }}; + ($files:expr) => {{ $files.iter().map(|file| file.chdir(wd)).collect() }}; } macro_rules! map { - ($map:expr) => {{ - $map - .iter() - .map(|(urn, file)| file.chdir(wd).map(|file| (urn.clone(), file))) - .collect::>()? - }}; + ($map:expr) => {{ $map.iter().map(|(urn, file)| (urn.clone(), file.chdir(wd))).collect() }}; } let w = UrlBuf::from(wd); - Ok(match self { + match self { Self::Full(_, files, cha) => Self::Full(w, files!(files), *cha), Self::Part(_, files, ticket) => Self::Part(w, files!(files), *ticket), Self::Done(_, cha, ticket) => Self::Done(w, *cha, *ticket), @@ -124,7 +118,7 @@ impl FilesOp { Self::Deleting(_, urns) => Self::Deleting(w, urns.clone()), Self::Updating(_, map) => Self::Updating(w, map!(map)), Self::Upserting(_, map) => Self::Upserting(w, map!(map)), - }) + } } pub fn diff_recoverable(&self, contains: impl Fn(&UrlBuf) -> bool) -> (Vec, Vec) { diff --git a/yazi-fs/src/path/clean.rs b/yazi-fs/src/path/clean.rs index a2ef3f74..7e5b2e9a 100644 --- a/yazi-fs/src/path/clean.rs +++ b/yazi-fs/src/path/clean.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use yazi_shared::{loc::LocBuf, path::{PathDyn, PathLike}, pool::InternStr, url::{AsUrl, Url, UrlBuf, UrlCow, UrlLike}}; +use yazi_shared::{loc::LocBuf, path::PathDyn, pool::InternStr, url::{AsUrl, Url, UrlBuf, UrlCow, UrlLike}}; pub fn clean_url<'a>(url: impl Into>) -> UrlBuf { let cow: UrlCow = url.into(); diff --git a/yazi-fs/src/path/expand.rs b/yazi-fs/src/path/expand.rs index 5baba83f..562f06db 100644 --- a/yazi-fs/src/path/expand.rs +++ b/yazi-fs/src/path/expand.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, path::PathBuf}; -use yazi_shared::{FromWtf8Vec, loc::LocBuf, path::{AsPath, PathBufDyn, PathCow, PathDyn, PathLike}, pool::InternStr, url::{AsUrl, Url, UrlBuf, UrlCow, UrlLike}}; +use yazi_shared::{FromWtf8Vec, loc::LocBuf, path::{PathBufDyn, PathCow, PathDyn, PathLike}, pool::InternStr, url::{AsUrl, Url, UrlBuf, UrlCow, UrlLike}}; use crate::{CWD, path::clean_url}; @@ -16,18 +16,13 @@ fn expand_url_impl<'a>(url: Url<'a>) -> UrlCow<'a> { let n_rest = expand_variables(o_rest); let n_urn = expand_variables(o_urn); - let rest_diff = - n_rest.as_path().components().count() as isize - o_rest.components().count() as isize; - let urn_diff = - n_urn.as_path().components().count() as isize - o_urn.components().count() as isize; + 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().components().count() as isize; let urn_count = url.urn().components().count() as isize; - let mut path = PathBufDyn::with_capacity( - url.kind(), - n_base.as_path().len() + n_rest.as_path().len() + n_urn.as_path().len(), - ); + let mut path = PathBufDyn::with_capacity(url.kind(), n_base.len() + n_rest.len() + n_urn.len()); path.try_extend([n_base, n_rest, n_urn]).expect("extend original parts should not fail"); let loc = LocBuf::::with( @@ -77,7 +72,7 @@ pub fn absolute_url<'a>(url: impl Into>) -> UrlCow<'a> { absolute_url fn absolute_url_impl<'a>(url: UrlCow<'a>) -> UrlCow<'a> { if url.kind().is_virtual() { - return url.into(); + return url; } let path = url.loc().as_os().expect("must be a local path"); diff --git a/yazi-fs/src/provider/local/local.rs b/yazi-fs/src/provider/local/local.rs index d79e79e6..abfaaf71 100644 --- a/yazi-fs/src/provider/local/local.rs +++ b/yazi-fs/src/provider/local/local.rs @@ -1,6 +1,6 @@ use std::{io, path::{Path, PathBuf}, sync::Arc}; -use yazi_shared::{path::{AsPathDyn, PathBufDyn}, scheme::SchemeKind, url::{Url, UrlBuf, UrlCow}}; +use yazi_shared::{path::{AsPath, PathBufDyn}, scheme::SchemeKind, url::{Url, UrlBuf, UrlCow}}; use crate::{cha::Cha, path::absolute_url, provider::{Attrs, Provider}}; @@ -31,9 +31,9 @@ impl<'a> Provider for Local<'a> { #[inline] async fn copy

(&self, to: P, attrs: Attrs) -> io::Result where - P: AsPathDyn, + P: AsPath, { - let to = to.as_path_dyn().to_os_owned()?; + let to = to.as_path().to_os_owned()?; let from = self.path.to_owned(); Self::copy_impl(from, to, attrs).await } @@ -47,9 +47,9 @@ impl<'a> Provider for Local<'a> { #[inline] async fn hard_link

(&self, to: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { - let to = to.as_path_dyn().as_os()?; + let to = to.as_path().as_os()?; tokio::fs::hard_link(self.path, to).await } @@ -62,7 +62,7 @@ impl<'a> Provider for Local<'a> { #[inline] async fn new<'b>(url: Url<'b>) -> io::Result> { match url { - Url::Regular(loc) | Url::Search { loc, .. } => Ok(Self::Me { url, path: loc.as_path() }), + Url::Regular(loc) | Url::Search { loc, .. } => Ok(Self::Me { url, path: loc.as_inner() }), Url::Archive { .. } | Url::Sftp { .. } => { Err(io::Error::new(io::ErrorKind::InvalidInput, format!("Not a local URL: {url:?}"))) } @@ -101,9 +101,9 @@ impl<'a> Provider for Local<'a> { #[inline] async fn rename

(&self, to: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { - let to = to.as_path_dyn().as_os()?; + let to = to.as_path().as_os()?; tokio::fs::rename(self.path, to).await } @@ -111,12 +111,12 @@ impl<'a> Provider for Local<'a> { #[inline] async fn symlink(&self, original: P, _is_dir: F) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, F: AsyncFnOnce() -> io::Result, { #[cfg(unix)] { - let original = original.as_path_dyn().as_os()?; + let original = original.as_path().as_os()?; tokio::fs::symlink(original, self.path).await } #[cfg(windows)] @@ -130,9 +130,9 @@ impl<'a> Provider for Local<'a> { #[inline] async fn symlink_dir

(&self, original: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { - let original = original.as_path_dyn().as_os()?; + let original = original.as_path().as_os()?; #[cfg(unix)] { @@ -147,9 +147,9 @@ impl<'a> Provider for Local<'a> { #[inline] async fn symlink_file

(&self, original: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { - let original = original.as_path_dyn().as_os()?; + let original = original.as_path().as_os()?; #[cfg(unix)] { diff --git a/yazi-fs/src/provider/traits.rs b/yazi-fs/src/provider/traits.rs index 52ed3ea6..3a92b04d 100644 --- a/yazi-fs/src/provider/traits.rs +++ b/yazi-fs/src/provider/traits.rs @@ -2,7 +2,7 @@ use std::io; use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; use yazi_macro::ok_or_not_found; -use yazi_shared::{path::{AsPathDyn, PathBufDyn, PathLike}, strand::StrandCow, url::{AsUrl, Url, UrlBuf}}; +use yazi_shared::{path::{AsPath, PathBufDyn}, strand::StrandCow, url::{AsUrl, Url, UrlBuf}}; use crate::{cha::{Cha, ChaType}, provider::Attrs}; @@ -21,7 +21,7 @@ pub trait Provider: Sized { fn copy

(&self, to: P, attrs: Attrs) -> impl Future> where - P: AsPathDyn; + P: AsPath; fn create(&self) -> impl Future> { async move { self.gate().write(true).create(true).truncate(true).open(self.url()).await } @@ -69,7 +69,7 @@ pub trait Provider: Sized { fn hard_link

(&self, to: P) -> impl Future> where - P: AsPathDyn; + P: AsPath; fn metadata(&self) -> impl Future>; @@ -144,23 +144,23 @@ pub trait Provider: Sized { fn rename

(&self, to: P) -> impl Future> where - P: AsPathDyn; + P: AsPath; fn symlink(&self, original: P, _is_dir: F) -> impl Future> where - P: AsPathDyn, + P: AsPath, F: AsyncFnOnce() -> io::Result; fn symlink_dir

(&self, original: P) -> impl Future> where - P: AsPathDyn, + P: AsPath, { self.symlink(original, async || Ok(true)) } fn symlink_file

(&self, original: P) -> impl Future> where - P: AsPathDyn, + P: AsPath, { self.symlink(original, async || Ok(false)) } diff --git a/yazi-fs/src/sorter.rs b/yazi-fs/src/sorter.rs index 6c747cbd..debac466 100644 --- a/yazi-fs/src/sorter.rs +++ b/yazi-fs/src/sorter.rs @@ -1,7 +1,7 @@ use std::cmp::Ordering; use hashbrown::HashMap; -use yazi_shared::{LcgRng, natsort, path::{PathBufDyn, PathLike}, strand::StrandLike, translit::Transliterator, url::UrlLike}; +use yazi_shared::{LcgRng, natsort, path::PathBufDyn, translit::Transliterator, url::UrlLike}; use crate::{File, SortBy}; diff --git a/yazi-fs/src/url.rs b/yazi-fs/src/url.rs index 12171d36..958fbfd2 100644 --- a/yazi-fs/src/url.rs +++ b/yazi-fs/src/url.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, ffi::OsStr, path::{Path, PathBuf}}; -use yazi_shared::{path::{PathDyn, PathLike}, url::{AsUrl, Url, UrlBuf, UrlCow}}; +use yazi_shared::{path::PathDyn, url::{AsUrl, Url, UrlBuf, UrlCow}}; use crate::{FsHash128, FsScheme, path::PercentEncoding}; @@ -48,7 +48,7 @@ impl<'a> FsUrl<'a> for Url<'a> { fn unified_path(self) -> Cow<'a, Path> { match self { - Self::Regular(loc) | Self::Search { loc, .. } => loc.as_path().into(), + Self::Regular(loc) | Self::Search { loc, .. } => loc.as_inner().into(), Self::Archive { .. } | Self::Sftp { .. } => { self.cache().expect("non-local URL should have a cache path").into() } @@ -63,7 +63,7 @@ impl FsUrl<'_> for UrlBuf { fn unified_path(self) -> Cow<'static, Path> { match self { - Self::Regular(loc) | Self::Search { loc, .. } => loc.into_path().into(), + Self::Regular(loc) | Self::Search { loc, .. } => loc.into_inner().into(), Self::Archive { .. } | Self::Sftp { .. } => { self.cache().expect("non-local URL should have a cache path").into() } @@ -78,8 +78,8 @@ impl<'a> FsUrl<'a> for UrlCow<'a> { fn unified_path(self) -> Cow<'a, Path> { match self { - Self::Regular(loc) | Self::Search { loc, .. } => loc.into_path().into(), - Self::RegularRef(loc) | Self::SearchRef { loc, .. } => loc.as_path().into(), + Self::Regular(loc) | Self::Search { loc, .. } => loc.into_inner().into(), + Self::RegularRef(loc) | Self::SearchRef { loc, .. } => loc.as_inner().into(), Self::Archive { .. } | Self::ArchiveRef { .. } | Self::Sftp { .. } | Self::SftpRef { .. } => { self.cache().expect("non-local URL should have a cache path").into() } diff --git a/yazi-macro/Cargo.toml b/yazi-macro/Cargo.toml index e267afe7..2b803c84 100644 --- a/yazi-macro/Cargo.toml +++ b/yazi-macro/Cargo.toml @@ -7,3 +7,6 @@ authors = [ "sxyazi " ] description = "Yazi macros" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" + +[lints] +workspace = true diff --git a/yazi-packing/Cargo.toml b/yazi-packing/Cargo.toml index 47f5a87e..38fea9c8 100644 --- a/yazi-packing/Cargo.toml +++ b/yazi-packing/Cargo.toml @@ -8,18 +8,21 @@ description = "Yazi packing" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" - [package.metadata.deb] - name = "yazi" - license-file = [ "../LICENSE", "0" ] - depends = "file, ffmpeg, 7zip, jq, poppler-utils, fd-find|fd, ripgrep, fzf, zoxide, imagemagick, xsel|xclip|wl-clipboard" - recommends = "bash-completion" - extended-description-file = "README.md" - section = "utility" - priority = "optional" - assets = [ - [ "target/release/ya", "usr/bin/", "755" ], - [ "target/release/yazi", "usr/bin/", "755" ], - [ "../README.md", "usr/share/doc/yazi/README", "644" ], - [ "../yazi-cli/completions/ya.bash", "usr/share/bash-completion/completions/ya", "644" ], - [ "../yazi-boot/completions/yazi.bash", "usr/share/bash-completion/completions/yazi", "644" ], - ] +[lints] +workspace = true + +[package.metadata.deb] +name = "yazi" +license-file = [ "../LICENSE", "0" ] +depends = "file, ffmpeg, 7zip, jq, poppler-utils, fd-find|fd, ripgrep, fzf, zoxide, imagemagick, xsel|xclip|wl-clipboard" +recommends = "bash-completion" +extended-description-file = "README.md" +section = "utility" +priority = "optional" +assets = [ + [ "target/release/ya", "usr/bin/", "755" ], + [ "target/release/yazi", "usr/bin/", "755" ], + [ "../README.md", "usr/share/doc/yazi/README", "644" ], + [ "../yazi-cli/completions/ya.bash", "usr/share/bash-completion/completions/ya", "644" ], + [ "../yazi-boot/completions/yazi.bash", "usr/share/bash-completion/completions/yazi", "644" ], +] diff --git a/yazi-parser/Cargo.toml b/yazi-parser/Cargo.toml index 37d7d295..c8e75256 100644 --- a/yazi-parser/Cargo.toml +++ b/yazi-parser/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi command parser" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [features] default = [ "vendored-lua" ] vendored-lua = [ "mlua/vendored" ] diff --git a/yazi-parser/src/cmp/show.rs b/yazi-parser/src/cmp/show.rs index 05478e81..8984c6c9 100644 --- a/yazi-parser/src/cmp/show.rs +++ b/yazi-parser/src/cmp/show.rs @@ -2,7 +2,7 @@ use std::path::MAIN_SEPARATOR_STR; use anyhow::bail; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::{Id, event::CmdCow, path::PathBufDyn, strand::{StrandBuf, StrandBufLike}, url::UrlBuf}; +use yazi_shared::{Id, event::CmdCow, path::PathBufDyn, strand::{StrandBuf, StrandLike}, url::UrlBuf}; #[derive(Debug)] pub struct ShowOpt { diff --git a/yazi-parser/src/mgr/copy.rs b/yazi-parser/src/mgr/copy.rs index 1496f154..55d5d30f 100644 --- a/yazi-parser/src/mgr/copy.rs +++ b/yazi-parser/src/mgr/copy.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, str::FromStr}; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; use serde::Deserialize; -use yazi_shared::{SStr, event::CmdCow, strand::{AsStrandDyn, StrandLike}}; +use yazi_shared::{SStr, event::CmdCow, strand::AsStrand}; #[derive(Debug)] pub struct CopyOpt { @@ -49,16 +49,16 @@ impl FromStr for CopySeparator { impl CopySeparator { pub fn transform(self, s: &T) -> Cow<'_, [u8]> where - T: ?Sized + AsStrandDyn, + T: ?Sized + AsStrand, { #[cfg(windows)] if self == Self::Unix { - use yazi_shared::strand::{StrandBufLike, StrandCow}; - return match s.as_strand_dyn().backslash_to_slash() { + use yazi_shared::strand::StrandCow; + return match s.as_strand().backslash_to_slash() { StrandCow::Borrowed(s) => s.encoded_bytes().into(), StrandCow::Owned(s) => s.into_encoded_bytes().into(), }; } - Cow::Borrowed(s.as_strand_dyn().encoded_bytes()) + Cow::Borrowed(s.as_strand().encoded_bytes()) } } diff --git a/yazi-plugin/Cargo.toml b/yazi-plugin/Cargo.toml index 2af7df35..b573428c 100644 --- a/yazi-plugin/Cargo.toml +++ b/yazi-plugin/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi plugin system" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [features] default = [ "vendored-lua" ] vendored-lua = [ "mlua/vendored" ] diff --git a/yazi-proxy/Cargo.toml b/yazi-proxy/Cargo.toml index d794362f..a2ec00ac 100644 --- a/yazi-proxy/Cargo.toml +++ b/yazi-proxy/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi event proxy" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-config = { path = "../yazi-config", version = "25.9.15" } yazi-macro = { path = "../yazi-macro", version = "25.9.15" } diff --git a/yazi-scheduler/Cargo.toml b/yazi-scheduler/Cargo.toml index 31228597..fda89e5e 100644 --- a/yazi-scheduler/Cargo.toml +++ b/yazi-scheduler/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi task scheduler" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-config = { path = "../yazi-config", version = "25.9.15" } yazi-dds = { path = "../yazi-dds", version = "25.9.15" } diff --git a/yazi-scheduler/src/prework/prework.rs b/yazi-scheduler/src/prework/prework.rs index c9ec0aa0..e87eabe5 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, path::PathLike, url::{UrlBuf, UrlLike}}; +use yazi_shared::{event::CmdCow, 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().owned(), s))), + HashMap::from_iter(buf.into_iter().map(|(u, s)| (u.urn().into(), s))), ) .emit(); }); diff --git a/yazi-sftp/Cargo.toml b/yazi-sftp/Cargo.toml index dcd6bb41..20939e46 100644 --- a/yazi-sftp/Cargo.toml +++ b/yazi-sftp/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi SFTP client" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] bitflags = { workspace = true } parking_lot = { workspace = true } diff --git a/yazi-sftp/src/byte_str.rs b/yazi-sftp/src/byte_str.rs index db545ac5..97f2d156 100644 --- a/yazi-sftp/src/byte_str.rs +++ b/yazi-sftp/src/byte_str.rs @@ -17,7 +17,7 @@ impl<'a> From<&'a str> for ByteStr<'a> { fn from(value: &'a str) -> Self { ByteStr(Cow::Borrowed(value.as_bytes())) } } -impl<'a> From<&'a ByteStr<'a>> for ByteStr<'a> { +impl<'a> From<&'a Self> for ByteStr<'a> { fn from(value: &'a ByteStr) -> Self { ByteStr(Cow::Borrowed(&value.0)) } } @@ -67,7 +67,7 @@ impl<'a> ByteStr<'a> { } } - pub fn join(&self, other: impl Into>) -> PathBuf { + pub fn join(&self, other: impl Into) -> PathBuf { let other = other.into(); match self.to_path() { Cow::Borrowed(p) => p.join(other.to_path()), diff --git a/yazi-shared/Cargo.toml b/yazi-shared/Cargo.toml index c19fe6bf..5544bcb2 100644 --- a/yazi-shared/Cargo.toml +++ b/yazi-shared/Cargo.toml @@ -9,6 +9,9 @@ homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" rust-version = "1.91.0" +[lints] +workspace = true + [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 bc82c1e9..261322ed 100644 --- a/yazi-shared/src/data/data.rs +++ b/yazi-shared/src/data/data.rs @@ -15,8 +15,8 @@ pub enum Data { Integer(i64), Number(f64), String(SStr), - List(Vec), - Dict(HashMap), + List(Vec), + Dict(HashMap), Id(Id), #[serde(skip_deserializing)] Url(UrlBuf), diff --git a/yazi-shared/src/loc/able.rs b/yazi-shared/src/loc/able.rs new file mode 100644 index 00000000..4b5b2cd2 --- /dev/null +++ b/yazi-shared/src/loc/able.rs @@ -0,0 +1,142 @@ +use std::{ffi::{OsStr, OsString}, fmt::Debug, hash::Hash}; + +use crate::{path::{AsPath, AsPathView}, strand::AsStrandView}; + +// --- LocAble +pub trait LocAble<'p> +where + Self: Copy + AsStrandView<'p, Self::Strand<'p>>, +{ + type Strand<'a>: StrandAble<'a> + StrandAbleImpl<'a>; + type Owned: LocBufAble + LocBufAbleImpl + Into; + type Components<'a>: Clone + DoubleEndedIterator + AsStrandView<'a, Self::Strand<'a>>; +} + +impl<'p> LocAble<'p> for &'p std::path::Path { + type Components<'a> = std::path::Components<'a>; + type Owned = std::path::PathBuf; + type Strand<'a> = &'a OsStr; +} + +// --- LocBufAble +pub trait LocBufAble +where + Self: 'static + AsPath + Default, +{ + type Strand<'a>: StrandAble<'a>; + type Borrowed<'a>: LocAble<'a> + + LocAbleImpl<'a> + + AsPathView<'a, Self::Borrowed<'a>> + + Debug + + Hash; +} + +impl LocBufAble for std::path::PathBuf { + type Borrowed<'a> = &'a std::path::Path; + type Strand<'a> = &'a OsStr; +} + +// --- StrandAble +pub trait StrandAble<'a>: Copy {} + +impl<'a> StrandAble<'a> for &'a OsStr {} + +// --- LocAbleImpl +pub(super) trait LocAbleImpl<'p>: LocAble<'p> { + fn as_encoded_bytes(self) -> &'p [u8]; + + fn components(self) -> Self::Components<'p>; + + fn empty() -> Self; + + fn file_name(self) -> Option>; + + unsafe fn from_encoded_bytes_unchecked(bytes: &'p [u8]) -> Self; + + fn join<'a, T>(self, path: T) -> Self::Owned + where + T: AsStrandView<'a, Self::Strand<'a>>; + + fn len(self) -> usize { self.as_encoded_bytes().len() } + + fn strip_prefix<'a, T>(self, base: T) -> Option + where + T: AsStrandView<'a, Self::Strand<'a>>; + + fn to_path_buf(self) -> Self::Owned; +} + +impl<'p> LocAbleImpl<'p> for &'p std::path::Path { + fn as_encoded_bytes(self) -> &'p [u8] { self.as_os_str().as_encoded_bytes() } + + fn components(self) -> Self::Components<'p> { self.components() } + + fn empty() -> Self { std::path::Path::new("") } + + fn file_name(self) -> Option> { self.file_name() } + + unsafe fn from_encoded_bytes_unchecked(bytes: &'p [u8]) -> Self { + std::path::Path::new(unsafe { OsStr::from_encoded_bytes_unchecked(bytes) }) + } + + fn join<'a, T>(self, path: T) -> Self::Owned + where + T: AsStrandView<'a, Self::Strand<'a>>, + { + self.join(path.as_strand_view()) + } + + fn strip_prefix<'a, T>(self, base: T) -> Option + where + T: AsStrandView<'a, Self::Strand<'a>>, + { + self.strip_prefix(base.as_strand_view()).ok() + } + + fn to_path_buf(self) -> Self::Owned { self.to_path_buf() } +} + +// --- LocBufAbleImpl +pub(super) trait LocBufAbleImpl: LocBufAble { + fn as_encoded_bytes(&self) -> &[u8] { self.borrow().as_encoded_bytes() } + + fn borrow(&self) -> Self::Borrowed<'_>; + + unsafe fn from_encoded_bytes_unchecked(bytes: Vec) -> Self; + + fn into_encoded_bytes(self) -> Vec; + + fn len(&self) -> usize { self.borrow().len() } + + fn set_file_name<'a, T>(&mut self, name: T) + where + T: AsStrandView<'a, Self::Strand<'a>>; +} + +impl LocBufAbleImpl for std::path::PathBuf { + fn borrow(&self) -> Self::Borrowed<'_> { self.as_path() } + + unsafe fn from_encoded_bytes_unchecked(bytes: Vec) -> Self { + Self::from(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }) + } + + fn into_encoded_bytes(self) -> Vec { self.into_os_string().into_encoded_bytes() } + + fn set_file_name<'a, T>(&mut self, name: T) + where + T: AsStrandView<'a, Self::Strand<'a>>, + { + self.set_file_name(name.as_strand_view()) + } +} + +// --- StrandAbleImpl +pub(super) trait StrandAbleImpl<'a>: StrandAble<'a> { + fn as_encoded_bytes(self) -> &'a [u8]; + + fn len(self) -> usize { self.as_encoded_bytes().len() } +} + +impl<'a> StrandAbleImpl<'a> for &'a OsStr { + fn as_encoded_bytes(self) -> &'a [u8] { self.as_encoded_bytes() } +} diff --git a/yazi-shared/src/loc/buf.rs b/yazi-shared/src/loc/buf.rs index 24f5f325..171f9247 100644 --- a/yazi-shared/src/loc/buf.rs +++ b/yazi-shared/src/loc/buf.rs @@ -1,11 +1,11 @@ -use std::{cmp, ffi::OsStr, fmt::{self, Debug, Formatter}, hash::{Hash, Hasher}, marker::PhantomData, ops::Deref, path::PathBuf}; +use std::{cmp, ffi::OsStr, fmt::{self, Debug, Formatter}, hash::{Hash, Hasher}, marker::PhantomData, mem, ops::Deref, path::PathBuf}; use anyhow::Result; -use crate::{loc::Loc, path::{AsPathDyn, AsPathView, PathBufLike, PathBufUnsafeExt, PathDyn, PathLike, PathUnsafeExt, SetNameError}, scheme::SchemeKind, strand::AsStrandView}; +use crate::{loc::{Loc, LocAble, LocAbleImpl, LocBufAble, LocBufAbleImpl}, path::{AsPath, AsPathView, PathDyn, SetNameError}, scheme::SchemeKind, strand::AsStrandView}; -#[derive(Clone, Default, Eq)] -pub struct LocBuf { +#[derive(Clone, Default, Eq, PartialEq)] +pub struct LocBuf

{ pub(super) inner: P, pub(super) uri: usize, pub(super) urn: usize, @@ -13,7 +13,7 @@ pub struct LocBuf { impl

Deref for LocBuf

where - P: PathBufLike, + P: LocBufAble, { type Target = P; @@ -25,37 +25,30 @@ impl AsRef for LocBuf { fn as_ref(&self) -> &std::path::Path { self.inner.as_ref() } } -impl AsPathDyn for LocBuf +impl AsPath for LocBuf where - T: PathBufLike + AsPathDyn, + T: LocBufAble + AsPath, { - fn as_path_dyn(&self) -> PathDyn<'_> { self.inner.as_path_dyn() } + fn as_path(&self) -> PathDyn<'_> { self.inner.as_path() } } -impl AsPathDyn for &LocBuf +impl AsPath for &LocBuf where - T: PathBufLike + AsPathDyn, + T: LocBufAble + AsPath, { - fn as_path_dyn(&self) -> PathDyn<'_> { self.inner.as_path_dyn() } -} - -impl

PartialEq for LocBuf

-where - P: PathBufLike + PartialEq, -{ - fn eq(&self, other: &Self) -> bool { self.inner == other.inner } + fn as_path(&self) -> PathDyn<'_> { self.inner.as_path() } } impl

Ord for LocBuf

where - P: PathBufLike + Ord, + P: LocBufAble + Ord, { fn cmp(&self, other: &Self) -> cmp::Ordering { self.inner.cmp(&other.inner) } } impl

PartialOrd for LocBuf

where - P: PathBufLike + PartialOrd, + P: LocBufAble + PartialOrd, { fn partial_cmp(&self, other: &Self) -> Option { self.inner.partial_cmp(&other.inner) @@ -65,8 +58,7 @@ where // --- Hash impl

Hash for LocBuf

where - P: PathBufLike + PathBufUnsafeExt, - for<'a> P::Borrowed<'a>: PathUnsafeExt<'a>, + P: LocBufAble + LocBufAbleImpl, for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>, { fn hash(&self, state: &mut H) { self.as_loc().hash(state) } @@ -74,8 +66,7 @@ where impl

Debug for LocBuf

where - P: PathBufLike + PathBufUnsafeExt + Debug, - for<'a> P::Borrowed<'a>: PathUnsafeExt<'a>, + P: LocBufAble + LocBufAbleImpl + Debug, for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>, { fn fmt(&self, f: &mut Formatter) -> fmt::Result { @@ -89,8 +80,7 @@ where impl

From

for LocBuf

where - P: PathBufLike + PathBufUnsafeExt, - for<'a> P::Borrowed<'a>: PathUnsafeExt<'a>, + P: LocBufAble + LocBufAbleImpl, for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>, { fn from(path: P) -> Self { @@ -99,7 +89,7 @@ where let mut bytes = path.into_encoded_bytes(); bytes.truncate(len); - Self { inner: unsafe { P::from_encoded_bytes(bytes) }, uri, urn } + Self { inner: unsafe { P::from_encoded_bytes_unchecked(bytes) }, uri, urn } } } @@ -109,29 +99,28 @@ impl> From<&T> for LocBuf { impl

LocBuf

where - P: PathBufLike + PathBufUnsafeExt, - for<'a> P::Borrowed<'a>: PathUnsafeExt<'a>, + P: LocBufAble + LocBufAbleImpl, for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>, { pub fn new<'a, S>(path: P, base: S, trail: S) -> Self where - S: for<'b> AsStrandView<'a, as PathLike<'b>>::Strand<'a>>, + S: for<'b> AsStrandView<'a, as LocAble<'b>>::Strand<'a>>, { let loc = Self::from(path); let Loc { inner, uri, urn, _phantom } = Loc::new(&loc.inner, base, trail); - debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes()); + debug_assert!(inner.as_encoded_bytes() == loc.inner.as_encoded_bytes()); Self { inner: loc.inner, uri, urn } } pub fn with(path: P, uri: usize, urn: usize) -> Result where - for<'a> P::Borrowed<'a>: PathLike<'a>, + for<'a> P::Borrowed<'a>: LocAble<'a>, { let loc = Self::from(path); let Loc { inner, uri, urn, _phantom } = Loc::with(&loc.inner, uri, urn)?; - debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes()); + debug_assert!(inner.as_encoded_bytes() == loc.inner.as_encoded_bytes()); Ok(Self { inner: loc.inner, uri, urn }) } @@ -142,18 +131,18 @@ where let loc = Self::from(path.into()); let Loc { inner, uri, urn, _phantom } = Loc::zeroed(&loc.inner); - debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes()); + debug_assert!(inner.as_encoded_bytes() == loc.inner.as_encoded_bytes()); Self { inner: loc.inner, uri, urn } } pub fn floated<'a, S>(path: P, base: S) -> Self where - S: for<'b> AsStrandView<'a, as PathLike<'b>>::Strand<'a>>, + S: for<'b> AsStrandView<'a, as LocAble<'b>>::Strand<'a>>, { let loc = Self::from(path); let Loc { inner, uri, urn, _phantom } = Loc::floated(&loc.inner, base); - debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes()); + debug_assert!(inner.as_encoded_bytes() == loc.inner.as_encoded_bytes()); Self { inner: loc.inner, uri, urn } } @@ -161,7 +150,7 @@ where let loc = Self::from(path); let Loc { inner, uri, urn, _phantom } = Loc::saturated(&loc.inner, kind); - debug_assert!(inner.encoded_bytes() == loc.inner.encoded_bytes()); + debug_assert!(inner.as_encoded_bytes() == loc.inner.as_encoded_bytes()); Self { inner: loc.inner, uri, urn } } @@ -176,7 +165,7 @@ where } #[inline] - pub fn to_path(&self) -> P + pub fn to_inner(&self) -> P where P: Clone, { @@ -184,14 +173,14 @@ where } #[inline] - pub fn into_path(self) -> P { self.inner } + pub fn into_inner(self) -> P { self.inner } pub fn try_set_name<'a, T>(&mut self, name: T) -> Result<(), SetNameError> where T: AsStrandView<'a, P::Strand<'a>>, { let old = self.inner.len(); - self.mutate(|path| path.try_set_name(name))?; + self.mutate(|path| path.set_file_name(name)); let new = self.len(); if new == old { @@ -216,19 +205,19 @@ where } #[inline] - pub fn rebase<'a, 'b>(&'a self, base: P::Borrowed<'b>) -> Result + pub fn rebase<'a, 'b>(&'a self, base: P::Borrowed<'b>) -> Self where 'a: 'b, - for<'c> as PathLike<'c>>::Owned: Into, + for<'c> as LocAble<'c>>::Owned: Into, { - let mut loc: Self = base.try_join(self.uri())?.into(); + let mut loc: Self = base.join(self.uri()).into(); (loc.uri, loc.urn) = (self.uri, self.urn); - Ok(loc) + loc } #[inline] fn mutate T>(&mut self, f: F) -> T { - let mut inner = self.inner.take(); + let mut inner = mem::take(&mut self.inner); let result = f(&mut inner); self.inner = Self::from(inner).inner; result @@ -238,8 +227,7 @@ where // FIXME: macro impl

LocBuf

where - P: PathBufLike + PathBufUnsafeExt, - for<'a> P::Borrowed<'a>: PathUnsafeExt<'a>, + P: LocBufAble + LocBufAbleImpl, for<'a> &'a P: AsPathView<'a, P::Borrowed<'a>>, { #[inline] @@ -259,19 +247,6 @@ where #[inline] pub fn has_trail(&self) -> bool { self.as_loc().has_trail() } - - #[inline] - pub fn name(&self) -> Option< as PathLike<'_>>::Strand<'_>> { - self.as_loc().name() - } - - #[inline] - pub fn stem(&self) -> Option< as PathLike<'_>>::Strand<'_>> { - self.as_loc().stem() - } - - #[inline] - pub fn ext(&self) -> Option< as PathLike<'_>>::Strand<'_>> { self.as_loc().ext() } } impl LocBuf { @@ -290,22 +265,22 @@ mod tests { let loc: LocBuf = Path::new("/").into(); assert_eq!(loc.uri().as_os_str(), OsStr::new("/")); assert_eq!(loc.urn().as_os_str(), OsStr::new("")); - assert_eq!(loc.name(), None); + assert_eq!(loc.file_name(), None); assert_eq!(loc.base().as_os_str(), OsStr::new("")); assert_eq!(loc.trail().as_os_str(), OsStr::new("/")); let loc: LocBuf = Path::new("/root").into(); - assert_eq!(loc.uri().as_os_str(), OsStr::new("root")); + assert_eq!(loc.uri().as_os_str(), OsStr::new("/root")); assert_eq!(loc.urn().as_os_str(), OsStr::new("root")); - assert_eq!(loc.name().unwrap(), OsStr::new("root")); - assert_eq!(loc.base().as_os_str(), OsStr::new("/")); + assert_eq!(loc.file_name().unwrap(), OsStr::new("root")); + assert_eq!(loc.base().as_os_str(), OsStr::new("")); assert_eq!(loc.trail().as_os_str(), OsStr::new("/")); let loc: LocBuf = Path::new("/root/code/foo/").into(); - assert_eq!(loc.uri().as_os_str(), OsStr::new("foo")); + assert_eq!(loc.uri().as_os_str(), OsStr::new("/root/code/foo")); assert_eq!(loc.urn().as_os_str(), OsStr::new("foo")); - assert_eq!(loc.name().unwrap(), OsStr::new("foo")); - assert_eq!(loc.base().as_os_str(), OsStr::new("/root/code/")); + assert_eq!(loc.file_name().unwrap(), OsStr::new("foo")); + assert_eq!(loc.base().as_os_str(), OsStr::new("")); assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/code/")); } @@ -314,42 +289,42 @@ mod tests { let loc = LocBuf::::with("/".into(), 0, 0)?; assert_eq!(loc.uri().as_os_str(), OsStr::new("")); assert_eq!(loc.urn().as_os_str(), OsStr::new("")); - assert_eq!(loc.name(), None); + assert_eq!(loc.file_name(), None); assert_eq!(loc.base().as_os_str(), OsStr::new("/")); assert_eq!(loc.trail().as_os_str(), OsStr::new("/")); let loc = LocBuf::::with("/root/code/".into(), 1, 1)?; assert_eq!(loc.uri().as_os_str(), OsStr::new("code")); assert_eq!(loc.urn().as_os_str(), OsStr::new("code")); - assert_eq!(loc.name().unwrap(), OsStr::new("code")); + assert_eq!(loc.file_name().unwrap(), OsStr::new("code")); assert_eq!(loc.base().as_os_str(), OsStr::new("/root/")); assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/")); let loc = LocBuf::::with("/root/code/foo//".into(), 2, 1)?; assert_eq!(loc.uri().as_os_str(), OsStr::new("code/foo")); assert_eq!(loc.urn().as_os_str(), OsStr::new("foo")); - assert_eq!(loc.name().unwrap(), OsStr::new("foo")); + assert_eq!(loc.file_name().unwrap(), OsStr::new("foo")); assert_eq!(loc.base().as_os_str(), OsStr::new("/root/")); assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/code/")); let loc = LocBuf::::with("/root/code/foo//".into(), 2, 2)?; assert_eq!(loc.uri().as_os_str(), OsStr::new("code/foo")); assert_eq!(loc.urn().as_os_str(), OsStr::new("code/foo")); - assert_eq!(loc.name().unwrap(), OsStr::new("foo")); + assert_eq!(loc.file_name().unwrap(), OsStr::new("foo")); assert_eq!(loc.base().as_os_str(), OsStr::new("/root/")); assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/")); let loc = LocBuf::::with("/root/code/foo//bar/".into(), 2, 2)?; assert_eq!(loc.uri().as_os_str(), OsStr::new("foo//bar")); assert_eq!(loc.urn().as_os_str(), OsStr::new("foo//bar")); - assert_eq!(loc.name().unwrap(), OsStr::new("bar")); + assert_eq!(loc.file_name().unwrap(), OsStr::new("bar")); assert_eq!(loc.base().as_os_str(), OsStr::new("/root/code/")); assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/code/")); let loc = LocBuf::::with("/root/code/foo//bar/".into(), 3, 2)?; assert_eq!(loc.uri().as_os_str(), OsStr::new("code/foo//bar")); assert_eq!(loc.urn().as_os_str(), OsStr::new("foo//bar")); - assert_eq!(loc.name().unwrap(), OsStr::new("bar")); + assert_eq!(loc.file_name().unwrap(), OsStr::new("bar")); assert_eq!(loc.base().as_os_str(), OsStr::new("/root/")); assert_eq!(loc.trail().as_os_str(), OsStr::new("/root/code/")); Ok(()) diff --git a/yazi-shared/src/loc/loc.rs b/yazi-shared/src/loc/loc.rs index a24d5801..182284d7 100644 --- a/yazi-shared/src/loc/loc.rs +++ b/yazi-shared/src/loc/loc.rs @@ -2,7 +2,8 @@ use std::{hash::{Hash, Hasher}, marker::PhantomData, ops::Deref, path::Path}; use anyhow::{Result, bail}; -use crate::{loc::LocBuf, path::{AsPathDyn, AsPathView, PathBufLike, PathDyn, PathLike, PathUnsafeExt}, scheme::SchemeKind, strand::{AsStrandView, StrandLike}}; +use super::LocAbleImpl; +use crate::{loc::{LocAble, LocBuf, LocBufAble, StrandAbleImpl}, path::{AsPath, AsPathView, PathDyn}, scheme::SchemeKind, strand::AsStrandView}; #[derive(Clone, Copy, Debug)] pub struct Loc<'p, P = &'p Path> { @@ -14,25 +15,25 @@ pub struct Loc<'p, P = &'p Path> { impl<'p, P> Default for Loc<'p, P> where - P: PathLike<'p>, + P: LocAble<'p> + LocAbleImpl<'p>, { - fn default() -> Self { Self { inner: P::default(), uri: 0, urn: 0, _phantom: PhantomData } } + fn default() -> Self { Self { inner: P::empty(), uri: 0, urn: 0, _phantom: PhantomData } } } impl<'p, P> Deref for Loc<'p, P> where - P: PathLike<'p>, + P: LocAble<'p>, { type Target = P; fn deref(&self) -> &Self::Target { &self.inner } } -impl<'p, P> AsPathDyn for Loc<'p, P> +impl<'p, P> AsPath for Loc<'p, P> where - P: PathLike<'p> + AsPathDyn, + P: LocAble<'p> + AsPath, { - fn as_path_dyn(&self) -> PathDyn<'_> { self.inner.as_path_dyn() } + fn as_path(&self) -> PathDyn<'_> { self.inner.as_path() } } // FIXME: remove @@ -43,34 +44,34 @@ impl AsRef for Loc<'_, &std::path::Path> { // --- Hash impl<'p, P> Hash for Loc<'p, P> where - P: PathLike<'p> + Hash, + P: LocAble<'p> + Hash, { fn hash(&self, state: &mut H) { self.inner.hash(state) } } -impl<'p, P> From> for LocBuf<

>::Owned> +impl<'p, P> From> for LocBuf<

>::Owned> where - P: PathLike<'p>, -

>::Owned: PathBufLike, + P: LocAble<'p> + LocAbleImpl<'p>, +

>::Owned: LocBufAble, { fn from(value: Loc<'p, P>) -> Self { - Self { inner: value.inner.owned(), uri: value.uri, urn: value.urn } + Self { inner: value.inner.to_path_buf(), uri: value.uri, urn: value.urn } } } // --- Eq impl<'p, P> PartialEq for Loc<'p, P> where - P: PathLike<'p> + PartialEq, + P: LocAble<'p> + PartialEq, { fn eq(&self, other: &Self) -> bool { self.inner == other.inner } } -impl<'p, P> Eq for Loc<'p, P> where P: PathLike<'p> + Eq {} +impl<'p, P> Eq for Loc<'p, P> where P: LocAble<'p> + Eq {} impl<'p, P> Loc<'p, P> where - P: PathLike<'p> + PathUnsafeExt<'p>, + P: LocAble<'p> + LocAbleImpl<'p>, { pub fn new<'a, T, S>(path: T, base: S, trail: S) -> Self where @@ -78,8 +79,8 @@ where S: AsStrandView<'a, P::Strand<'a>>, { let mut loc = Self::bare(path); - loc.uri = loc.inner.try_strip_prefix(base).expect("Loc must start with the given base").len(); - loc.urn = loc.inner.try_strip_prefix(trail).expect("Loc must start with the given trail").len(); + loc.uri = loc.inner.strip_prefix(base).expect("Loc must start with the given base").len(); + loc.urn = loc.inner.strip_prefix(trail).expect("Loc must start with the given trail").len(); loc } @@ -105,10 +106,10 @@ where bail!("URI exceeds the entire URL"); } if i == urn { - loc.urn = loc.try_strip_prefix(it.clone())?.len(); + loc.urn = loc.strip_prefix(it.clone()).unwrap().len(); } if i == uri { - loc.uri = loc.try_strip_prefix(it)?.len(); + loc.uri = loc.strip_prefix(it).unwrap().len(); break; } } @@ -120,19 +121,20 @@ where T: AsPathView<'p, P>, { let path = path.as_path_view(); - let Some(name) = path.name() else { - let uri = path.len(); + let Some(name) = path.file_name() else { + let uri = path.strip_prefix(P::empty()).unwrap().len(); return Self { inner: path, uri, urn: 0, _phantom: PhantomData }; }; let name_len = name.len(); - let prefix_len = - unsafe { name.encoded_bytes().as_ptr().offset_from_unsigned(path.encoded_bytes().as_ptr()) }; + let prefix_len = unsafe { + name.as_encoded_bytes().as_ptr().offset_from_unsigned(path.as_encoded_bytes().as_ptr()) + }; - let bytes = path.encoded_bytes(); + let bytes = &path.as_encoded_bytes()[..prefix_len + name_len]; Self { - inner: unsafe { P::from_encoded_bytes(&bytes[..prefix_len + name_len]) }, - uri: name_len, + inner: unsafe { P::from_encoded_bytes_unchecked(bytes) }, + uri: bytes.len(), urn: name_len, _phantom: PhantomData, } @@ -153,7 +155,7 @@ where S: AsStrandView<'a, P::Strand<'a>>, { let mut loc = Self::bare(path); - loc.uri = loc.inner.try_strip_prefix(base).expect("Loc must start with the given base").len(); + loc.uri = loc.inner.strip_prefix(base).expect("Loc must start with the given base").len(); loc } @@ -173,29 +175,35 @@ where pub fn as_loc(self) -> Self { self } #[inline] - pub fn as_path(self) -> P { self.inner } + pub fn as_inner(self) -> P { self.inner } #[inline] - pub fn is_empty(self) -> bool { self.inner.is_empty() } + pub fn is_empty(self) -> bool { self.inner.len() == 0 } #[inline] pub fn uri(self) -> P { unsafe { - P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(self.inner.len() - self.uri..)) + P::from_encoded_bytes_unchecked( + self.inner.as_encoded_bytes().get_unchecked(self.inner.len() - self.uri..), + ) } } #[inline] pub fn urn(self) -> P { unsafe { - P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(self.inner.len() - self.urn..)) + P::from_encoded_bytes_unchecked( + self.inner.as_encoded_bytes().get_unchecked(self.inner.len() - self.urn..), + ) } } #[inline] pub fn base(self) -> P { unsafe { - P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(..self.inner.len() - self.uri)) + P::from_encoded_bytes_unchecked( + self.inner.as_encoded_bytes().get_unchecked(..self.inner.len() - self.uri), + ) } } @@ -205,7 +213,9 @@ where #[inline] pub fn trail(self) -> P { unsafe { - P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(..self.inner.len() - self.urn)) + P::from_encoded_bytes_unchecked( + self.inner.as_encoded_bytes().get_unchecked(..self.inner.len() - self.urn), + ) } } @@ -222,9 +232,9 @@ where unsafe { ( - P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(base)), - P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(rest)), - P::from_encoded_bytes(self.inner.encoded_bytes().get_unchecked(urn)), + P::from_encoded_bytes_unchecked(self.inner.as_encoded_bytes().get_unchecked(base)), + P::from_encoded_bytes_unchecked(self.inner.as_encoded_bytes().get_unchecked(rest)), + P::from_encoded_bytes_unchecked(self.inner.as_encoded_bytes().get_unchecked(urn)), ) } } diff --git a/yazi-shared/src/loc/mod.rs b/yazi-shared/src/loc/mod.rs index d89a0329..5b4556e9 100644 --- a/yazi-shared/src/loc/mod.rs +++ b/yazi-shared/src/loc/mod.rs @@ -1 +1,3 @@ -yazi_macro::mod_flat!(buf loc); +#![allow(private_bounds)] + +yazi_macro::mod_flat!(able buf loc); diff --git a/yazi-shared/src/path/buf.rs b/yazi-shared/src/path/buf.rs index 97a135e5..d9273700 100644 --- a/yazi-shared/src/path/buf.rs +++ b/yazi-shared/src/path/buf.rs @@ -1,62 +1,128 @@ -use std::{fmt::Debug, hash::Hash}; +use std::ffi::{OsStr, OsString}; -use crate::{path::{AsPath, AsPathView, PathBufDyn, PathLike, SetNameError, StartsWithError}, strand::{AsStrandView, StrandLike}}; +use hashbrown::Equivalent; +use serde::Serialize; -pub trait PathBufLike -where - Self: 'static + AsPath, -{ - type Strand<'a>: StrandLike<'a>; - type Borrowed<'a>: PathLike<'a> + AsPathView<'a, Self::Borrowed<'a>> + Debug + Hash; +use crate::{FromWtf8, path::{AsPath, PathBufDynError, PathDyn, PathKind, SetNameError}, strand::{AsStrand, Strand, StrandError}}; - fn borrow(&self) -> Self::Borrowed<'_>; - - fn encoded_bytes(&self) -> &[u8] { self.borrow().encoded_bytes() } - - fn into_dyn(self) -> PathBufDyn; - - fn into_encoded_bytes(self) -> Vec; - - fn is_empty(&self) -> bool { self.borrow().is_empty() } - - fn len(&self) -> usize { self.borrow().len() } - - fn to_str(&self) -> Result<&str, std::str::Utf8Error> { self.borrow().to_str() } - - fn try_set_name<'a, T>(&mut self, name: T) -> Result<(), SetNameError> - where - T: AsStrandView<'a, Self::Strand<'a>>; - - fn try_starts_with<'a, T>(&self, base: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>; - - fn take(&mut self) -> Self; +// --- PathBufDyn +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +#[serde(untagged)] +pub enum PathBufDyn { + Os(std::path::PathBuf), } -impl PathBufLike for std::path::PathBuf { - type Borrowed<'a> = &'a std::path::Path; - type Strand<'a> = &'a std::ffi::OsStr; - - fn borrow(&self) -> Self::Borrowed<'_> { self.as_path() } - - fn into_dyn(self) -> PathBufDyn { PathBufDyn::Os(self) } - - fn into_encoded_bytes(self) -> Vec { self.into_os_string().into_encoded_bytes() } - - fn try_set_name<'a, T>(&mut self, name: T) -> Result<(), SetNameError> - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(self.set_file_name(name.as_strand_view())) - } - - fn try_starts_with<'a, T>(&self, base: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(self.starts_with(base.as_strand_view())) - } - - fn take(&mut self) -> Self { std::mem::take(self) } +impl From for PathBufDyn { + fn from(value: std::path::PathBuf) -> Self { Self::Os(value) } +} + +impl From> for PathBufDyn { + fn from(value: PathDyn<'_>) -> Self { value.to_owned() } +} + +impl TryFrom for std::path::PathBuf { + type Error = PathBufDynError; + + fn try_from(value: PathBufDyn) -> Result { value.into_os() } +} + +impl PartialEq> for PathBufDyn { + fn eq(&self, other: &PathDyn<'_>) -> bool { self.as_path() == *other } +} + +impl PartialEq> for &PathBufDyn { + fn eq(&self, other: &PathDyn<'_>) -> bool { self.as_path() == *other } +} + +impl Equivalent> for PathBufDyn { + fn equivalent(&self, key: &PathDyn<'_>) -> bool { self.as_path() == *key } +} + +impl PathBufDyn { + #[inline] + pub unsafe fn from_encoded_bytes(kind: K, bytes: Vec) -> Self + where + K: Into, + { + match kind.into() { + PathKind::Os => Self::Os(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }.into()), + } + } + + pub fn into_encoded_bytes(self) -> Vec { + match self { + Self::Os(p) => p.into_os_string().into_encoded_bytes(), + } + } + + #[inline] + pub fn into_os(self) -> Result { + Ok(match self { + Self::Os(p) => p, + }) + } + + #[inline] + pub fn new(kind: PathKind) -> Self { + match kind { + PathKind::Os => Self::Os(std::path::PathBuf::new()), + } + } + + #[inline] + pub fn os(path: impl Into) -> Self { Self::Os(path.into()) } + + pub fn try_extend(&mut self, paths: T) -> Result<(), StrandError> + where + T: IntoIterator, + T::Item: AsPath, + { + for p in paths { + self.try_push(p)?; + } + Ok(()) + } + + pub fn try_push(&mut self, path: T) -> Result<(), StrandError> + where + T: AsPath, + { + let path = path.as_path(); + Ok(match self { + Self::Os(p) => p.push(path.as_os()?), + }) + } + + pub fn try_set_name(&mut self, name: T) -> Result<(), SetNameError> + where + T: AsStrand, + { + Ok(match (self, name.as_strand()) { + (Self::Os(p), Strand::Os(q)) => p.set_file_name(q), + (Self::Os(p), Strand::Utf8(q)) => p.set_file_name(q), + (Self::Os(p), Strand::Bytes(b)) => { + p.set_file_name(OsStr::from_wtf8(b).map_err(|_| SetNameError::FromWtf8)?) + } + }) + } + + pub fn with(kind: K, strand: T) -> Result + where + K: Into, + T: AsStrand, + { + let s = strand.as_strand(); + Ok(match kind.into() { + PathKind::Os => Self::Os(std::path::PathBuf::from(s.as_os()?)), + }) + } + + pub fn with_capacity(kind: K, capacity: usize) -> Self + where + K: Into, + { + match kind.into() { + PathKind::Os => Self::Os(std::path::PathBuf::with_capacity(capacity)), + } + } } diff --git a/yazi-shared/src/path/conversion.rs b/yazi-shared/src/path/conversion.rs index 8eee3e53..963fef8b 100644 --- a/yazi-shared/src/path/conversion.rs +++ b/yazi-shared/src/path/conversion.rs @@ -1,96 +1,50 @@ -use std::{borrow::Cow, ffi::OsStr}; +use std::ffi::OsStr; use super::{PathBufDyn, PathDyn}; -use crate::path::{PathBufLike, PathCow, PathLike}; +use crate::path::PathCow; // --- AsPath pub trait AsPath { - fn as_path(&self) -> impl PathLike<'_>; + fn as_path(&self) -> PathDyn<'_>; } impl AsPath for OsStr { - fn as_path(&self) -> impl PathLike<'_> { std::path::Path::new(self) } + fn as_path(&self) -> PathDyn<'_> { PathDyn::Os(self.as_ref()) } } impl AsPath for &OsStr { - fn as_path(&self) -> impl PathLike<'_> { std::path::Path::new(self) } + fn as_path(&self) -> PathDyn<'_> { PathDyn::Os(self.as_ref()) } } impl AsPath for std::path::Path { - fn as_path(&self) -> impl PathLike<'_> { self } + fn as_path(&self) -> PathDyn<'_> { PathDyn::Os(self) } } impl AsPath for std::path::PathBuf { - fn as_path(&self) -> impl PathLike<'_> { self.as_path() } + fn as_path(&self) -> PathDyn<'_> { PathDyn::Os(self) } } impl AsPath for PathDyn<'_> { - fn as_path(&self) -> impl PathLike<'_> { *self } + fn as_path(&self) -> PathDyn<'_> { *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() } -} - -impl AsPath for PathCow<'_> { - fn as_path(&self) -> impl PathLike<'_> { + fn as_path(&self) -> PathDyn<'_> { match self { - PathCow::Borrowed(p) => *p, - PathCow::Owned(p) => p.into(), + Self::Os(p) => PathDyn::Os(p), } } } -// --- AsPathDyn -pub trait AsPathDyn { - fn as_path_dyn(&self) -> PathDyn<'_>; +impl AsPath for &PathBufDyn { + fn as_path(&self) -> PathDyn<'_> { (*self).as_path() } } -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::Path { - fn as_path_dyn(&self) -> PathDyn<'_> { 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() } -} - -impl AsPathDyn for PathCow<'_> { - fn as_path_dyn(&self) -> PathDyn<'_> { +impl AsPath for PathCow<'_> { + fn as_path(&self) -> PathDyn<'_> { match self { - Self::Borrowed(p) => p.as_path_dyn(), - Self::Owned(p) => p.as_path_dyn(), + PathCow::Borrowed(p) => *p, + PathCow::Owned(p) => p.as_path(), } } } @@ -101,5 +55,5 @@ pub trait AsPathRef<'a> { } impl<'a> AsPathRef<'a> for PathDyn<'a> { - fn as_path_ref(self) -> PathDyn<'a> { self } + fn as_path_ref(self) -> Self { self } } diff --git a/yazi-shared/src/path/cow.rs b/yazi-shared/src/path/cow.rs index 238a11b5..a2523944 100644 --- a/yazi-shared/src/path/cow.rs +++ b/yazi-shared/src/path/cow.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use anyhow::Result; -use crate::{IntoOsStr, path::{AsPathDyn, PathBufDyn, PathBufLike, PathDyn, PathLike}}; +use crate::{IntoOsStr, path::{AsPath, PathBufDyn, PathDyn}}; // --- PathCow pub enum PathCow<'a> { @@ -25,8 +25,8 @@ impl From> for PathBufDyn { impl PartialEq<&str> for PathCow<'_> { fn eq(&self, other: &&str) -> bool { match self { - Self::Borrowed(s) => s.as_path_dyn() == *other, - Self::Owned(s) => s.as_path_dyn() == *other, + Self::Borrowed(s) => s.as_path() == *other, + Self::Owned(s) => s.as_path() == *other, } } } @@ -41,16 +41,8 @@ impl<'a> PathCow<'a> { pub fn into_owned(self) -> PathBufDyn { match self { - Self::Borrowed(s) => s.to_buf_dyn(), + Self::Borrowed(s) => s.to_owned(), Self::Owned(s) => s, } } - - // FIXME: remove, instead implement PathLike for PathCow - pub fn encoded_bytes(&self) -> &[u8] { - match self { - Self::Borrowed(s) => s.encoded_bytes(), - Self::Owned(s) => s.encoded_bytes(), - } - } } diff --git a/yazi-shared/src/path/dyn.rs b/yazi-shared/src/path/dyn.rs deleted file mode 100644 index 777f2ef7..00000000 --- a/yazi-shared/src/path/dyn.rs +++ /dev/null @@ -1,411 +0,0 @@ -use std::ffi::OsStr; - -use anyhow::Result; -use hashbrown::Equivalent; -use serde::Serialize; - -use super::{AsPathView, RsplitOnceError, StartsWithError}; -use crate::{FromWtf8, Utf8BytePredictor, path::{AsPathDyn, EndsWithError, JoinError, PathBufDynError, PathBufLike, PathBufUnsafeExt, PathDynError, PathKind, PathLike, SetNameError, StripPrefixError}, scheme::SchemeKind, strand::{AsStrandDyn, AsStrandView, Strand, StrandError}}; - -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum PathDyn<'p> { - Os(&'p std::path::Path), -} - -impl<'a> AsPathView<'a, PathDyn<'a>> for PathDyn<'a> { - fn as_path_view(self) -> PathDyn<'a> { self } -} - -impl<'a> AsPathView<'a, PathDyn<'a>> for std::path::Components<'a> { - fn as_path_view(self) -> PathDyn<'a> { PathDyn::Os(self.as_path()) } -} - -impl<'a> From<&'a std::path::Path> for PathDyn<'a> { - fn from(value: &'a std::path::Path) -> Self { Self::Os(value) } -} - -impl<'a> From<&'a PathBufDyn> for PathDyn<'a> { - fn from(value: &'a PathBufDyn) -> Self { value.borrow() } -} - -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 PartialEq<&std::path::Path> for PathDyn<'_> { - fn eq(&self, other: &&std::path::Path) -> bool { matches!(*self, PathDyn::Os(p) if p == *other) } -} - -impl PartialEq<&str> for PathDyn<'_> { - fn eq(&self, other: &&str) -> bool { - match self { - PathDyn::Os(p) => p == other, - } - } -} - -impl Equivalent for PathDyn<'_> { - fn equivalent(&self, key: &PathBufDyn) -> bool { *self == key.borrow() } -} - -impl<'p> PathLike<'p> for PathDyn<'p> { - type Components<'a> = std::path::Components<'a>; - type Display<'a> = std::path::Display<'a>; - type Owned = PathBufDyn; - type Strand<'a> = Strand<'a>; - type View<'a> = PathDyn<'a>; - - fn as_dyn(self) -> PathDyn<'p> { self } - - fn components(self) -> Self::Components<'p> { - match self { - Self::Os(p) => p.components(), - } - } - - // 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(), - } - } - - fn ext(self) -> Option> { - Some(match self { - Self::Os(p) => p.extension()?.into(), - }) - } - - fn has_root(self) -> bool { - match self { - Self::Os(p) => p.has_root(), - } - } - - fn is_absolute(self) -> bool { - match self { - Self::Os(p) => p.is_absolute(), - } - } - - fn kind(self) -> PathKind { - match self { - Self::Os(_) => PathKind::Os, - } - } - - fn name(self) -> Option> { - Some(match self { - Self::Os(p) => p.file_name()?.into(), - }) - } - - 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()?), - }) - } - - fn stem(self) -> Option> { - Some(match self { - Self::Os(p) => p.file_stem()?.into(), - }) - } - - fn try_ends_with<'a, T>(self, child: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(match (self, child.as_strand_view()) { - (Self::Os(p), Strand::Os(q)) => p.ends_with(q), - (Self::Os(p), Strand::Utf8(q)) => p.ends_with(q), - (Self::Os(p), Strand::Bytes(b)) => { - p.ends_with(OsStr::from_wtf8(b).map_err(|_| EndsWithError)?) - } - }) - } - - fn try_join<'a, T>(self, path: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(match (self, path.as_strand_view()) { - (Self::Os(p), Strand::Os(q)) => Self::Owned::Os(p.join(q)), - (Self::Os(p), Strand::Utf8(q)) => Self::Owned::Os(p.join(q)), - (Self::Os(p), Strand::Bytes(b)) => { - Self::Owned::Os(p.join(OsStr::from_wtf8(b).map_err(|_| JoinError::FromWtf8)?)) - } - }) - } - - fn rsplit_pred<'a, T>(self, pred: T) -> Option<(Self, Self)> - where - T: Utf8BytePredictor, - { - match self { - PathDyn::Os(p) => p.rsplit_pred(pred).map(|(l, r)| (Self::Os(l), Self::Os(r))), - } - } - - fn try_rsplit_seq<'a, T>(self, pat: T) -> Result<(Self, Self), RsplitOnceError> - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - let pat = pat.as_strand_view(); - match self { - PathDyn::Os(p) => { - let (l, r) = p.try_rsplit_seq(pat.as_os().map_err(|_| RsplitOnceError::AsOs)?)?; - Ok((Self::Os(l), Self::Os(r))) - } - } - } - - fn try_starts_with<'a, T>(self, base: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(match (self, base.as_strand_view()) { - (Self::Os(p), Strand::Os(q)) => p.starts_with(q), - (Self::Os(p), Strand::Utf8(q)) => p.starts_with(q), - (Self::Os(p), Strand::Bytes(b)) => { - p.starts_with(OsStr::from_wtf8(b).map_err(|_| StartsWithError)?) - } - }) - } - - fn try_strip_prefix<'a, T>(self, base: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(match (self, base.as_strand_view()) { - (Self::Os(p), Strand::Os(q)) => Self::Os(p.strip_prefix(q)?), - (Self::Os(p), Strand::Utf8(q)) => Self::Os(p.strip_prefix(q)?), - (Self::Os(p), Strand::Bytes(b)) => { - Self::Os(p.strip_prefix(OsStr::from_wtf8(b).map_err(|_| StripPrefixError::WrongEncoding)?)?) - } - }) - } -} - -impl<'a> PathDyn<'a> { - #[inline] - pub fn os(path: &'a T) -> Self - where - T: ?Sized + AsRef, - { - Self::Os(path.as_ref()) - } - - #[inline] - pub fn as_os(self) -> Result<&'a std::path::Path, PathDynError> { - match self { - Self::Os(p) => Ok(p), - } - } - - #[inline] - pub fn to_os_owned(self) -> Result { - match self { - Self::Os(p) => Ok(p.to_owned()), - } - } - - pub fn with(kind: SchemeKind, strand: &'a T) -> Result - where - T: ?Sized + AsStrandDyn, - { - use SchemeKind as K; - - let s = strand.as_strand_dyn(); - Ok(match kind { - K::Regular | K::Search | K::Archive => Self::Os(std::path::Path::new(s.as_os()?)), - K::Sftp => Self::Os(std::path::Path::new(s.as_os()?)), // FIXME - }) - } - - #[inline] - pub unsafe fn from_encoded_bytes(kind: impl Into, bytes: &'a [u8]) -> Self { - match kind.into() { - PathKind::Os => Self::Os(unsafe { OsStr::from_encoded_bytes_unchecked(bytes) }.as_ref()), - } - } -} - -// --- PathBufDyn -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] -#[serde(untagged)] -pub enum PathBufDyn { - Os(std::path::PathBuf), -} - -impl From for PathBufDyn { - fn from(value: std::path::PathBuf) -> Self { Self::Os(value) } -} - -impl From<&PathBufDyn> for PathBufDyn { - fn from(value: &PathBufDyn) -> Self { value.clone() } -} - -impl TryFrom for std::path::PathBuf { - type Error = PathBufDynError; - - fn try_from(value: PathBufDyn) -> Result { value.into_os() } -} - -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 } -} - -impl PathBufLike for PathBufDyn { - type Borrowed<'a> = PathDyn<'a>; - type Strand<'a> = Strand<'a>; - - 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(), - } - } - - fn into_dyn(self) -> PathBufDyn { self } - - fn into_encoded_bytes(self) -> Vec { - match self { - Self::Os(p) => p.into_os_string().into_encoded_bytes(), - } - } - - fn try_set_name<'a, T>(&mut self, name: T) -> Result<(), SetNameError> - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(match (self, name.as_strand_view()) { - (Self::Os(p), Strand::Os(q)) => p.set_file_name(q), - (Self::Os(p), Strand::Utf8(q)) => p.set_file_name(q), - (Self::Os(p), Strand::Bytes(b)) => { - p.set_file_name(OsStr::from_wtf8(b).map_err(|_| SetNameError::FromWtf8)?) - } - }) - } - - fn try_starts_with<'a, T>(&self, base: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(match (self, base.as_strand_view()) { - (Self::Os(p), Strand::Os(q)) => p.starts_with(q), - (Self::Os(p), Strand::Utf8(q)) => p.starts_with(q), - (Self::Os(p), Strand::Bytes(b)) => { - p.starts_with(OsStr::from_wtf8(b).map_err(|_| StartsWithError)?) - } - }) - } - - fn take(&mut self) -> Self { - match self { - Self::Os(p) => Self::Os(std::mem::take(p)), - } - } -} - -impl PathBufDyn { - #[inline] - pub fn os(path: impl Into) -> Self { Self::Os(path.into()) } - - #[inline] - pub fn into_os(self) -> Result { - Ok(match self { - PathBufDyn::Os(p) => p, - }) - } - - #[inline] - pub fn new(kind: SchemeKind) -> Self { - use SchemeKind as K; - - match kind { - K::Regular | K::Search | K::Archive => Self::Os(std::path::PathBuf::new()), - K::Sftp => Self::Os(std::path::PathBuf::new()), // FIXME - } - } - - pub fn with(kind: SchemeKind, strand: T) -> Result - where - T: AsStrandDyn, - { - use SchemeKind as K; - - let s = strand.as_strand_dyn(); - Ok(match kind { - K::Regular | K::Search | K::Archive => Self::Os(std::path::PathBuf::from(s.as_os()?)), - K::Sftp => Self::Os(std::path::PathBuf::from(s.as_os()?)), // FIXME - }) - } - - pub fn with_capacity(kind: SchemeKind, capacity: usize) -> Self { - use SchemeKind as K; - match kind { - K::Regular | K::Search | K::Archive => Self::Os(std::path::PathBuf::with_capacity(capacity)), - K::Sftp => Self::Os(std::path::PathBuf::with_capacity(capacity)), // FIXME - } - } - - pub fn try_push(&mut self, path: T) -> Result<(), StrandError> - where - T: AsPathDyn, - { - let path = path.as_path_dyn(); - Ok(match self { - PathBufDyn::Os(p) => p.push(path.as_os()?), - }) - } - - pub fn try_extend(&mut self, paths: T) -> Result<(), StrandError> - where - T: IntoIterator, - T::Item: AsPathDyn, - { - for p in paths { - self.try_push(p)?; - } - Ok(()) - } - - #[inline] - pub unsafe fn from_encoded_bytes(kind: impl Into, bytes: Vec) -> Self { - match kind.into() { - PathKind::Os => Self::Os(unsafe { std::path::PathBuf::from_encoded_bytes(bytes) }), - } - } -} diff --git a/yazi-shared/src/path/error.rs b/yazi-shared/src/path/error.rs index 30f6dc14..8b28d274 100644 --- a/yazi-shared/src/path/error.rs +++ b/yazi-shared/src/path/error.rs @@ -16,7 +16,7 @@ pub enum JoinError { } impl From for std::io::Error { - fn from(err: JoinError) -> Self { std::io::Error::other(err) } + fn from(err: JoinError) -> Self { Self::other(err) } } // --- PathDynError @@ -27,7 +27,7 @@ pub enum PathDynError { } impl From for std::io::Error { - fn from(err: PathDynError) -> Self { std::io::Error::other(err) } + fn from(err: PathDynError) -> Self { Self::other(err) } } // --- PathBufDynError @@ -46,7 +46,7 @@ pub enum SetNameError { } impl From for std::io::Error { - fn from(err: SetNameError) -> Self { std::io::Error::other(err) } + fn from(err: SetNameError) -> Self { Self::other(err) } } // --- RsplitOnce @@ -61,6 +61,15 @@ pub enum RsplitOnceError { NotFound, } +impl From for RsplitOnceError { + fn from(err: StrandError) -> Self { + match err { + StrandError::AsOs => Self::AsOs, + StrandError::AsUtf8 => Self::AsUtf8, + } + } +} + // --- StartsWithError #[derive(Error, Debug)] #[error("calling starts_with on paths with different encodings")] diff --git a/yazi-shared/src/path/like.rs b/yazi-shared/src/path/like.rs new file mode 100644 index 00000000..99ee4b5e --- /dev/null +++ b/yazi-shared/src/path/like.rs @@ -0,0 +1,96 @@ +use std::borrow::Cow; + +use anyhow::Result; + +use crate::{Utf8BytePredictor, path::{AsPath, EndsWithError, JoinError, PathBufDyn, PathCow, PathDyn, PathDynError, PathKind, RsplitOnceError, StartsWithError, StripPrefixError}, strand::{AsStrand, Strand}}; + +pub trait PathLike: AsPath { + fn as_os(&self) -> Result<&std::path::Path, PathDynError> { self.as_path().as_os() } + + fn components(&self) -> std::path::Components<'_> { self.as_path().components() } + + fn display(&self) -> std::path::Display<'_> { self.as_path().display() } + + fn encoded_bytes(&self) -> &[u8] { self.as_path().encoded_bytes() } + + fn ext(&self) -> Option> { self.as_path().ext() } + + fn has_root(&self) -> bool { self.as_path().has_root() } + + fn is_absolute(&self) -> bool { self.as_path().is_absolute() } + + fn is_empty(&self) -> bool { self.as_path().is_empty() } + + #[cfg(unix)] + fn is_hidden(&self) -> bool { self.as_path().is_hidden() } + + fn kind(&self) -> PathKind { self.as_path().kind() } + + fn len(&self) -> usize { self.as_path().len() } + + fn name(&self) -> Option> { self.as_path().name() } + + fn parent(&self) -> Option> { self.as_path().parent() } + + fn rsplit_pred(&self, pred: T) -> Option<(PathDyn<'_>, PathDyn<'_>)> + where + T: Utf8BytePredictor, + { + self.as_path().rsplit_pred(pred) + } + + fn stem(&self) -> Option> { self.as_path().stem() } + + fn to_os_owned(&self) -> Result { self.as_path().to_os_owned() } + + fn to_owned(&self) -> PathBufDyn { self.as_path().to_owned() } + + fn to_str(&self) -> Result<&str, std::str::Utf8Error> { self.as_path().to_str() } + + fn to_string_lossy(&self) -> Cow<'_, str> { self.as_path().to_string_lossy() } + + fn try_ends_with(&self, child: T) -> Result + where + T: AsStrand, + { + self.as_path().try_ends_with(child) + } + + fn try_join(&self, path: T) -> Result + where + T: AsStrand, + { + self.as_path().try_join(path) + } + + fn try_rsplit_seq(&self, pat: T) -> Result<(PathDyn<'_>, PathDyn<'_>), RsplitOnceError> + where + T: AsStrand, + { + self.as_path().try_rsplit_seq(pat) + } + + fn try_starts_with(&self, base: T) -> Result + where + T: AsStrand, + { + self.as_path().try_starts_with(base) + } + + fn try_strip_prefix(&self, base: T) -> Result, StripPrefixError> + where + T: AsStrand, + { + self.as_path().try_strip_prefix(base) + } +} + +impl

From<&P> for PathBufDyn +where + P: PathLike, +{ + fn from(value: &P) -> Self { value.to_owned() } +} + +impl PathLike for PathBufDyn {} +impl PathLike for PathCow<'_> {} diff --git a/yazi-shared/src/path/mod.rs b/yazi-shared/src/path/mod.rs index 30fde723..e7691f0c 100644 --- a/yazi-shared/src/path/mod.rs +++ b/yazi-shared/src/path/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(buf component components conversion cow error kind path r#dyn r#unsafe view); +yazi_macro::mod_flat!(buf component components conversion cow error kind like path view); diff --git a/yazi-shared/src/path/path.rs b/yazi-shared/src/path/path.rs index 43e02dea..3ac95899 100644 --- a/yazi-shared/src/path/path.rs +++ b/yazi-shared/src/path/path.rs @@ -1,184 +1,250 @@ use std::{borrow::Cow, ffi::OsStr}; use anyhow::Result; +use hashbrown::Equivalent; -use crate::{BytesExt, Utf8BytePredictor, path::{AsPathView, EndsWithError, JoinError, PathBufDyn, PathBufLike, PathDyn, PathKind, RsplitOnceError, StartsWithError, StripPrefixError}, strand::{AsStrandView, StrandLike}}; +use super::{RsplitOnceError, StartsWithError}; +use crate::{BytesExt, FromWtf8, Utf8BytePredictor, path::{AsPath, EndsWithError, JoinError, PathBufDyn, PathDynError, PathKind, StripPrefixError}, strand::{AsStrand, Strand, StrandError}}; -pub trait PathLike<'p> -where - Self: Copy + AsPathView<'p, Self::View<'p>> + AsStrandView<'p, Self::Strand<'p>>, -{ - type Strand<'a>: StrandLike<'a>; - type Owned: PathBufLike + Into; - type View<'a>; - type Components<'a>: Clone - + DoubleEndedIterator - + AsPathView<'a, Self::View<'a>> - + AsStrandView<'a, Self::Strand<'a>>; - type Display<'a>: std::fmt::Display; +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum PathDyn<'p> { + Os(&'p std::path::Path), +} - fn as_dyn(self) -> PathDyn<'p>; +impl<'a> From<&'a std::path::Path> for PathDyn<'a> { + fn from(value: &'a std::path::Path) -> Self { Self::Os(value) } +} - fn components(self) -> Self::Components<'p>; +impl<'a> From<&'a PathBufDyn> for PathDyn<'a> { + fn from(value: &'a PathBufDyn) -> Self { value.as_path() } +} - fn default() -> Self; +impl PartialEq for PathDyn<'_> { + fn eq(&self, other: &PathBufDyn) -> bool { *self == other.as_path() } +} - fn display(self) -> Self::Display<'p>; +impl PartialEq> for &std::path::Path { + fn eq(&self, other: &PathDyn<'_>) -> bool { matches!(*other, PathDyn::Os(p) if p == *self) } +} - fn encoded_bytes(self) -> &'p [u8]; +impl PartialEq<&std::path::Path> for PathDyn<'_> { + fn eq(&self, other: &&std::path::Path) -> bool { matches!(*self, PathDyn::Os(p) if p == *other) } +} - fn ext(self) -> Option>; +impl PartialEq<&str> for PathDyn<'_> { + fn eq(&self, other: &&str) -> bool { + match self { + PathDyn::Os(p) => p == other, + } + } +} - fn has_root(self) -> bool; +impl Equivalent for PathDyn<'_> { + fn equivalent(&self, key: &PathBufDyn) -> bool { *self == key.as_path() } +} - fn is_absolute(self) -> bool; +impl<'p> PathDyn<'p> { + #[inline] + pub fn as_os(self) -> Result<&'p std::path::Path, PathDynError> { + match self { + Self::Os(p) => Ok(p), + } + } - fn is_empty(self) -> bool { self.encoded_bytes().is_empty() } + pub fn components(self) -> std::path::Components<'p> { + match self { + Self::Os(p) => p.components(), + } + } + + pub fn display(self) -> std::path::Display<'p> { + match self { + Self::Os(p) => p.display(), + } + } + + pub fn encoded_bytes(self) -> &'p [u8] { + match self { + Self::Os(p) => p.as_os_str().as_encoded_bytes(), + } + } + + pub fn ext(self) -> Option> { + Some(match self { + Self::Os(p) => p.extension()?.into(), + }) + } + + #[inline] + pub unsafe fn from_encoded_bytes(kind: K, bytes: &'p [u8]) -> Self + where + K: Into, + { + match kind.into() { + PathKind::Os => Self::Os(unsafe { OsStr::from_encoded_bytes_unchecked(bytes) }.as_ref()), + } + } + + pub fn has_root(self) -> bool { + match self { + Self::Os(p) => p.has_root(), + } + } + + pub fn is_absolute(self) -> bool { + match self { + Self::Os(p) => p.is_absolute(), + } + } + + pub fn is_empty(self) -> bool { self.encoded_bytes().is_empty() } #[cfg(unix)] - fn is_hidden(self) -> bool { + pub fn is_hidden(self) -> bool { self.name().is_some_and(|n| n.encoded_bytes().first() == Some(&b'.')) } - fn kind(self) -> PathKind; - - fn len(self) -> usize { self.encoded_bytes().len() } - - fn name(self) -> Option>; - - fn owned(self) -> Self::Owned; - - fn parent(self) -> Option; - - fn rsplit_pred(self, pred: T) -> Option<(Self, Self)> - where - T: Utf8BytePredictor; - - fn stem(self) -> Option>; - - fn to_str(self) -> Result<&'p str, std::str::Utf8Error> { str::from_utf8(self.encoded_bytes()) } - - fn to_string_lossy(self) -> Cow<'p, str> { String::from_utf8_lossy(self.encoded_bytes()) } - - fn to_buf_dyn(self) -> PathBufDyn { self.as_dyn().owned() } - - fn try_ends_with<'a, T>(self, child: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>; - - fn try_join<'a, T>(self, path: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>; - - fn try_rsplit_seq<'a, T>(self, pat: T) -> Result<(Self, Self), RsplitOnceError> - where - T: AsStrandView<'a, Self::Strand<'a>>; - - fn try_starts_with<'a, T>(self, base: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>; - - fn try_strip_prefix<'a, T>(self, base: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>; -} - -impl<'p> PathLike<'p> for &'p std::path::Path { - type Components<'a> = std::path::Components<'a>; - type Display<'a> = std::path::Display<'a>; - type Owned = std::path::PathBuf; - type Strand<'a> = &'a std::ffi::OsStr; - type View<'a> = &'a std::path::Path; - - fn as_dyn(self) -> PathDyn<'p> { PathDyn::Os(self) } - - fn components(self) -> Self::Components<'p> { self.components() } - - 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 ext(self) -> Option> { self.extension() } - - fn has_root(self) -> bool { self.has_root() } - - fn is_absolute(self) -> bool { self.is_absolute() } - - fn kind(self) -> PathKind { PathKind::Os } - - fn name(self) -> Option> { self.file_name() } - - fn owned(self) -> Self::Owned { self.to_path_buf() } - - fn parent(self) -> Option { self.parent() } - - fn stem(self) -> Option> { self.file_stem() } - - fn try_ends_with<'a, T>(self, child: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(self.ends_with(child.as_strand_view())) + pub fn kind(self) -> PathKind { + match self { + Self::Os(_) => PathKind::Os, + } } - fn try_join<'a, T>(self, path: T) -> Result - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - Ok(self.join(path.as_strand_view())) + pub fn len(self) -> usize { self.encoded_bytes().len() } + + pub fn name(self) -> Option> { + Some(match self { + Self::Os(p) => p.file_name()?.into(), + }) } - fn rsplit_pred<'a, T>(self, pred: T) -> Option<(Self, Self)> + #[inline] + pub fn os(path: &'p T) -> Self + where + T: ?Sized + AsRef, + { + Self::Os(path.as_ref()) + } + + pub fn parent(self) -> Option { + Some(match self { + Self::Os(p) => Self::Os(p.parent()?), + }) + } + + pub fn rsplit_pred(self, pred: T) -> Option<(Self, Self)> where T: Utf8BytePredictor, { - let b = self.encoded_bytes(); - let (left, right) = b.rsplit_pred_once(pred)?; - + let (a, b) = self.encoded_bytes().rsplit_pred_once(pred)?; Some(unsafe { - ( - OsStr::from_encoded_bytes_unchecked(left).as_ref(), - OsStr::from_encoded_bytes_unchecked(right).as_ref(), - ) + (Self::from_encoded_bytes(self.kind(), a), Self::from_encoded_bytes(self.kind(), b)) }) } - fn try_rsplit_seq<'a, T>(self, pat: T) -> Result<(Self, Self), RsplitOnceError> - where - T: AsStrandView<'a, Self::Strand<'a>>, - { - let b = self.encoded_bytes(); - let p = pat.as_strand_view().encoded_bytes(); + pub fn stem(self) -> Option> { + Some(match self { + Self::Os(p) => p.file_stem()?.into(), + }) + } + + #[inline] + pub fn to_os_owned(self) -> Result { + match self { + Self::Os(p) => Ok(p.to_owned()), + } + } + + pub fn to_owned(self) -> PathBufDyn { + match self { + Self::Os(p) => PathBufDyn::Os(p.to_path_buf()), + } + } + + pub fn to_str(self) -> Result<&'p str, std::str::Utf8Error> { + str::from_utf8(self.encoded_bytes()) + } + + pub fn to_string_lossy(self) -> Cow<'p, str> { String::from_utf8_lossy(self.encoded_bytes()) } + + pub fn try_ends_with(self, child: T) -> Result + where + T: AsStrand, + { + Ok(match (self, child.as_strand()) { + (Self::Os(p), Strand::Os(q)) => p.ends_with(q), + (Self::Os(p), Strand::Utf8(q)) => p.ends_with(q), + (Self::Os(p), Strand::Bytes(b)) => { + p.ends_with(OsStr::from_wtf8(b).map_err(|_| EndsWithError)?) + } + }) + } + + pub fn try_join(self, path: T) -> Result + where + T: AsStrand, + { + Ok(match (self, path.as_strand()) { + (Self::Os(p), Strand::Os(q)) => PathBufDyn::Os(p.join(q)), + (Self::Os(p), Strand::Utf8(q)) => PathBufDyn::Os(p.join(q)), + (Self::Os(p), Strand::Bytes(b)) => { + PathBufDyn::Os(p.join(OsStr::from_wtf8(b).map_err(|_| JoinError::FromWtf8)?)) + } + }) + } + + pub fn try_rsplit_seq(self, pat: T) -> Result<(Self, Self), RsplitOnceError> + where + T: AsStrand, + { + let pat = pat.as_strand(); + + let (a, b) = match self { + PathDyn::Os(p) => { + p.as_os_str().as_encoded_bytes().rsplit_seq_once(pat.as_os()?.as_encoded_bytes()) + } + } + .ok_or(RsplitOnceError::NotFound)?; - let (left, right) = b.rsplit_seq_once(p).ok_or(RsplitOnceError::NotFound)?; Ok(unsafe { - ( - OsStr::from_encoded_bytes_unchecked(left).as_ref(), - OsStr::from_encoded_bytes_unchecked(right).as_ref(), - ) + (Self::from_encoded_bytes(self.kind(), a), Self::from_encoded_bytes(self.kind(), b)) }) } - fn try_starts_with<'a, T>(self, base: T) -> Result + pub fn try_starts_with(self, base: T) -> Result where - T: AsStrandView<'a, Self::Strand<'a>>, + T: AsStrand, { - Ok(self.starts_with(base.as_strand_view())) + Ok(match (self, base.as_strand()) { + (Self::Os(p), Strand::Os(q)) => p.starts_with(q), + (Self::Os(p), Strand::Utf8(q)) => p.starts_with(q), + (Self::Os(p), Strand::Bytes(b)) => { + p.starts_with(OsStr::from_wtf8(b).map_err(|_| StartsWithError)?) + } + }) } - fn try_strip_prefix<'a, T>(self, base: T) -> Result + pub fn try_strip_prefix(self, base: T) -> Result where - T: AsStrandView<'a, Self::Strand<'a>>, + T: AsStrand, { - Ok(self.strip_prefix(base.as_strand_view())?) + Ok(match (self, base.as_strand()) { + (Self::Os(p), Strand::Os(q)) => Self::Os(p.strip_prefix(q)?), + (Self::Os(p), Strand::Utf8(q)) => Self::Os(p.strip_prefix(q)?), + (Self::Os(p), Strand::Bytes(b)) => { + Self::Os(p.strip_prefix(OsStr::from_wtf8(b).map_err(|_| StripPrefixError::WrongEncoding)?)?) + } + }) + } + + pub fn with(kind: K, strand: &'p T) -> Result + where + K: Into, + T: ?Sized + AsStrand, + { + let s = strand.as_strand(); + Ok(match kind.into() { + PathKind::Os => Self::Os(std::path::Path::new(s.as_os()?)), + }) } } - -impl<'a, P> From

for PathBufDyn -where - P: PathLike<'a>, -{ - fn from(value: P) -> Self { value.to_buf_dyn() } -} diff --git a/yazi-shared/src/path/unsafe.rs b/yazi-shared/src/path/unsafe.rs deleted file mode 100644 index 4bfcb847..00000000 --- a/yazi-shared/src/path/unsafe.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::ffi::OsString; - -// --- PathUnsafeExt -pub trait PathUnsafeExt<'p> { - unsafe fn from_encoded_bytes(bytes: &'p [u8]) -> Self; -} - -impl<'p> PathUnsafeExt<'p> for &'p std::path::Path { - unsafe fn from_encoded_bytes(bytes: &'p [u8]) -> Self { - std::path::Path::new(unsafe { std::ffi::OsStr::from_encoded_bytes_unchecked(bytes) }) - } -} - -// --- PathBufUnsafeExt -pub trait PathBufUnsafeExt { - unsafe fn from_encoded_bytes(bytes: Vec) -> Self; -} - -impl PathBufUnsafeExt for std::path::PathBuf { - unsafe fn from_encoded_bytes(bytes: Vec) -> Self { - Self::from(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }) - } -} diff --git a/yazi-shared/src/path/view.rs b/yazi-shared/src/path/view.rs index a23c8422..883977d9 100644 --- a/yazi-shared/src/path/view.rs +++ b/yazi-shared/src/path/view.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, ffi::OsStr}; -use crate::path::{AsPathDyn, PathDyn}; +use crate::path::{AsPath, PathDyn}; // --- AsPathView pub trait AsPathView<'a, T> { @@ -25,9 +25,9 @@ impl<'a> AsPathView<'a, &'a std::path::Path> for std::path::Components<'a> { impl<'a, T> AsPathView<'a, PathDyn<'a>> for &'a T where - T: AsPathDyn, + T: AsPath, { - fn as_path_view(self) -> PathDyn<'a> { self.as_path_dyn() } + fn as_path_view(self) -> PathDyn<'a> { self.as_path() } } impl<'a> AsPathView<'a, &'a std::path::Path> for &'a Cow<'_, OsStr> { diff --git a/yazi-shared/src/scheme/cow.rs b/yazi-shared/src/scheme/cow.rs index 3e16e4cb..641c298d 100644 --- a/yazi-shared/src/scheme/cow.rs +++ b/yazi-shared/src/scheme/cow.rs @@ -1,9 +1,9 @@ -use std::{borrow::Cow, ops::Not}; +use std::borrow::Cow; use anyhow::{Result, ensure}; use percent_encoding::percent_decode; -use crate::{path::{AsPath, PathCow, PathLike}, pool::{InternStr, SymbolCow}, scheme::{AsScheme, Scheme, SchemeKind, SchemeRef}, url::Url}; +use crate::{path::{PathCow, PathLike}, pool::{InternStr, SymbolCow}, scheme::{AsScheme, Scheme, SchemeKind, SchemeRef}, url::Url}; #[derive(Clone, Debug)] pub enum SchemeCow<'a> { @@ -144,11 +144,10 @@ impl<'a> SchemeCow<'a> { urn: Option, path: &PathCow, ) -> Result<(usize, usize)> { - let path = path.as_path(); Ok(match kind { SchemeKind::Regular => { ensure!(uri.is_none() && urn.is_none(), "Regular scheme cannot have ports"); - (path.is_empty().not() as usize, path.name().is_some() as usize) + (path.components().count(), path.name().is_some() as usize) } SchemeKind::Search => { let (uri, urn) = (uri.unwrap_or(0), urn.unwrap_or(0)); @@ -157,7 +156,7 @@ impl<'a> SchemeCow<'a> { } SchemeKind::Archive => (uri.unwrap_or(0), urn.unwrap_or(0)), SchemeKind::Sftp => { - let uri = uri.unwrap_or(path.is_empty().not() as usize); + let uri = uri.unwrap_or_else(|| path.components().count()); let urn = urn.unwrap_or(path.name().is_some() as usize); (uri, urn) } @@ -165,12 +164,7 @@ impl<'a> SchemeCow<'a> { } pub fn retrieve_ports(url: Url) -> (usize, usize) { - match url { - Url::Regular(loc) => (loc.is_empty().not() as usize, loc.file_name().is_some() as usize), - Url::Search { loc, .. } => (loc.uri().components().count(), loc.urn().components().count()), - Url::Archive { loc, .. } => (loc.uri().components().count(), loc.urn().components().count()), - Url::Sftp { loc, .. } => (loc.uri().components().count(), loc.urn().components().count()), - } + (url.uri().components().count(), url.urn().components().count()) } } diff --git a/yazi-shared/src/scheme/encode.rs b/yazi-shared/src/scheme/encode.rs index 7b97244c..f191d2d5 100644 --- a/yazi-shared/src/scheme/encode.rs +++ b/yazi-shared/src/scheme/encode.rs @@ -1,8 +1,8 @@ -use std::{fmt::{self, Display}, ops::Not}; +use std::fmt::{self, Display}; use percent_encoding::{AsciiSet, CONTROLS, PercentEncode, percent_encode}; -use crate::{path::PathLike, scheme::SchemeKind, url::Url}; +use crate::{scheme::SchemeKind, url::Url}; #[derive(Clone, Copy)] pub struct Encode<'a>(pub Url<'a>); @@ -39,7 +39,7 @@ impl<'a> Encode<'a> { SchemeKind::Regular => Ok(()), SchemeKind::Search | SchemeKind::Archive => w!(0, 0), SchemeKind::Sftp => { - w!(self.0.0.loc().is_empty().not() as usize, self.0.0.loc().name().is_some() as usize) + w!(self.0.0.loc().components().count(), self.0.0.loc().name().is_some() as usize) } } } diff --git a/yazi-shared/src/scheme/traits.rs b/yazi-shared/src/scheme/traits.rs index 5467fbf0..b8c64c21 100644 --- a/yazi-shared/src/scheme/traits.rs +++ b/yazi-shared/src/scheme/traits.rs @@ -13,10 +13,10 @@ impl AsScheme for Scheme { #[inline] fn as_scheme(&self) -> SchemeRef<'_> { match *self { - Scheme::Regular { uri, urn } => SchemeRef::Regular { uri, urn }, - Scheme::Search { ref domain, uri, urn } => SchemeRef::Search { domain, uri, urn }, - Scheme::Archive { ref domain, uri, urn } => SchemeRef::Archive { domain, uri, urn }, - Scheme::Sftp { ref domain, uri, urn } => SchemeRef::Sftp { domain, uri, urn }, + Self::Regular { uri, urn } => SchemeRef::Regular { uri, urn }, + Self::Search { ref domain, uri, urn } => SchemeRef::Search { domain, uri, urn }, + Self::Archive { ref domain, uri, urn } => SchemeRef::Archive { domain, uri, urn }, + Self::Sftp { ref domain, uri, urn } => SchemeRef::Sftp { domain, uri, urn }, } } } diff --git a/yazi-shared/src/strand/buf.rs b/yazi-shared/src/strand/buf.rs new file mode 100644 index 00000000..f5b53849 --- /dev/null +++ b/yazi-shared/src/strand/buf.rs @@ -0,0 +1,85 @@ +use std::ffi::OsString; + +use serde::Serialize; + +use crate::{path::PathDyn, scheme::SchemeKind, strand::{AsStrand, Strand, StrandError, StrandKind}}; + +// --- StrandBuf +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] +#[serde(untagged)] +pub enum StrandBuf { + Os(OsString), + Utf8(String), + Bytes(Vec), +} + +impl Default for StrandBuf { + fn default() -> Self { Self::Utf8(String::new()) } +} + +impl From for StrandBuf { + fn from(value: OsString) -> Self { Self::Os(value) } +} + +impl From for StrandBuf { + fn from(value: String) -> Self { Self::Utf8(value) } +} + +impl From> for StrandBuf { + fn from(value: PathDyn) -> Self { + match value { + PathDyn::Os(p) => Self::Os(p.as_os_str().to_owned()), + } + } +} + +impl PartialEq> for StrandBuf { + fn eq(&self, other: &Strand<'_>) -> bool { self.as_strand() == *other } +} + +impl StrandBuf { + pub fn clear(&mut self) { + match self { + Self::Os(buf) => buf.clear(), + Self::Utf8(buf) => buf.clear(), + Self::Bytes(buf) => buf.clear(), + } + } + + #[inline] + pub unsafe fn from_encoded_bytes(kind: impl Into, bytes: Vec) -> Self { + match kind.into() { + StrandKind::Os => Self::Os(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }), + StrandKind::Utf8 => Self::Utf8(unsafe { String::from_utf8_unchecked(bytes) }), + StrandKind::Bytes => Self::Bytes(bytes), + } + } + + pub fn into_encoded_bytes(self) -> Vec { + match self { + Self::Os(s) => s.into_encoded_bytes(), + Self::Utf8(s) => s.into_bytes(), + Self::Bytes(b) => b, + } + } + + pub fn try_push(&mut self, s: T) -> Result<(), StrandError> + where + T: AsStrand, + { + let s = s.as_strand(); + Ok(match self { + Self::Os(buf) => buf.push(s.as_os()?), + Self::Utf8(buf) => buf.push_str(s.as_utf8()?), + Self::Bytes(buf) => buf.extend(s.encoded_bytes()), + }) + } + + pub fn with_capacity(kind: SchemeKind, capacity: usize) -> Self { + use SchemeKind as K; + match kind { + K::Regular | K::Search | K::Archive => Self::Os(OsString::with_capacity(capacity)), + K::Sftp => Self::Os(OsString::with_capacity(capacity)), // FIXME + } + } +} diff --git a/yazi-shared/src/strand/conversion.rs b/yazi-shared/src/strand/conversion.rs index ad2ce1aa..5f21c101 100644 --- a/yazi-shared/src/strand/conversion.rs +++ b/yazi-shared/src/strand/conversion.rs @@ -1,159 +1,103 @@ use std::{borrow::Cow, ffi::{OsStr, OsString}}; -use crate::{path::{PathBufDyn, PathDyn}, strand::{Strand, StrandBuf, StrandBufLike, StrandCow, StrandLike}}; +use crate::{path::{PathBufDyn, PathDyn}, strand::{Strand, StrandBuf, StrandCow}}; // --- AsStrand pub trait AsStrand { - fn as_strand(&self) -> impl StrandLike<'_>; + fn as_strand(&self) -> Strand<'_>; } impl AsStrand for [u8] { - fn as_strand(&self) -> impl StrandLike<'_> { self } + fn as_strand(&self) -> Strand<'_> { Strand::Bytes(self) } } impl AsStrand for &[u8] { - fn as_strand(&self) -> impl StrandLike<'_> { *self } + fn as_strand(&self) -> Strand<'_> { Strand::Bytes(self) } } impl AsStrand for Vec { - fn as_strand(&self) -> impl StrandLike<'_> { self.as_slice() } + fn as_strand(&self) -> Strand<'_> { Strand::Bytes(self) } } impl AsStrand for str { - fn as_strand(&self) -> impl StrandLike<'_> { self } + fn as_strand(&self) -> Strand<'_> { Strand::Utf8(self) } } impl AsStrand for &str { - fn as_strand(&self) -> impl StrandLike<'_> { *self } + fn as_strand(&self) -> Strand<'_> { Strand::Utf8(self) } } impl AsStrand for String { - fn as_strand(&self) -> impl StrandLike<'_> { self.as_str() } + fn as_strand(&self) -> Strand<'_> { Strand::Utf8(self) } +} + +impl AsStrand for &String { + fn as_strand(&self) -> Strand<'_> { Strand::Utf8(self) } } impl AsStrand for OsStr { - fn as_strand(&self) -> impl StrandLike<'_> { self } + fn as_strand(&self) -> Strand<'_> { Strand::Os(self) } } impl AsStrand for &OsStr { - fn as_strand(&self) -> impl StrandLike<'_> { *self } + fn as_strand(&self) -> Strand<'_> { Strand::Os(self) } } impl AsStrand for OsString { - fn as_strand(&self) -> impl StrandLike<'_> { self.as_os_str() } + fn as_strand(&self) -> Strand<'_> { Strand::Os(self) } +} + +impl AsStrand for &std::path::Path { + fn as_strand(&self) -> Strand<'_> { Strand::Os(self.as_os_str()) } } impl AsStrand for Cow<'_, OsStr> { - fn as_strand(&self) -> impl StrandLike<'_> { AsRef::::as_ref(self) } + fn as_strand(&self) -> Strand<'_> { Strand::Os(self) } } impl AsStrand for PathDyn<'_> { - fn as_strand(&self) -> impl StrandLike<'_> { - match self { - Self::Os(p) => p.as_os_str(), - } - } -} - -impl AsStrand for &PathBufDyn { - fn as_strand(&self) -> impl StrandLike<'_> { - match self { - PathBufDyn::Os(p) => p.as_os_str(), - } - } -} - -impl AsStrand for Strand<'_> { - fn as_strand(&self) -> impl StrandLike<'_> { *self } -} - -impl AsStrand for StrandBuf { - fn as_strand(&self) -> impl StrandLike<'_> { self.borrow() } -} - -impl AsStrand for StrandCow<'_> { - fn as_strand(&self) -> impl StrandLike<'_> { - match self { - StrandCow::Borrowed(s) => *s, - StrandCow::Owned(s) => s.into(), - } - } -} - -impl AsStrand for &StrandCow<'_> { - fn as_strand(&self) -> impl StrandLike<'_> { (**self).as_strand() } -} - -// --- AsStrandDyn -pub trait AsStrandDyn { - fn as_strand_dyn(&self) -> Strand<'_>; -} - -impl AsStrandDyn for OsStr { - fn as_strand_dyn(&self) -> Strand<'_> { Strand::Os(self) } -} - -impl AsStrandDyn for &OsStr { - fn as_strand_dyn(&self) -> Strand<'_> { Strand::Os(self) } -} - -impl AsStrandDyn for OsString { - fn as_strand_dyn(&self) -> Strand<'_> { Strand::Os(self) } -} - -impl AsStrandDyn for &std::path::PathBuf { - fn as_strand_dyn(&self) -> Strand<'_> { Strand::Os(self.as_os_str()) } -} - -impl AsStrandDyn for &str { - fn as_strand_dyn(&self) -> Strand<'_> { Strand::Utf8(self) } -} - -impl AsStrandDyn for String { - fn as_strand_dyn(&self) -> Strand<'_> { Strand::Utf8(self) } -} - -impl AsStrandDyn for &String { - fn as_strand_dyn(&self) -> Strand<'_> { Strand::Utf8(self) } -} - -impl AsStrandDyn for Cow<'_, OsStr> { - fn as_strand_dyn(&self) -> Strand<'_> { Strand::Os(self) } -} - -impl AsStrandDyn for PathDyn<'_> { - fn as_strand_dyn(&self) -> Strand<'_> { + fn as_strand(&self) -> Strand<'_> { match self { Self::Os(p) => Strand::Os(p.as_os_str()), } } } -impl AsStrandDyn for &PathBufDyn { - fn as_strand_dyn(&self) -> Strand<'_> { +impl AsStrand for &PathBufDyn { + fn as_strand(&self) -> Strand<'_> { match self { PathBufDyn::Os(p) => Strand::Os(p.as_os_str()), } } } -impl AsStrandDyn for Strand<'_> { - fn as_strand_dyn(&self) -> Strand<'_> { *self } +impl AsStrand for Strand<'_> { + fn as_strand(&self) -> Strand<'_> { *self } } -impl AsStrandDyn for StrandBuf { - fn as_strand_dyn(&self) -> Strand<'_> { self.borrow() } -} - -impl AsStrandDyn for &StrandBuf { - fn as_strand_dyn(&self) -> Strand<'_> { (*self).borrow() } -} - -impl AsStrandDyn for StrandCow<'_> { - fn as_strand_dyn(&self) -> Strand<'_> { +impl AsStrand for StrandBuf { + fn as_strand(&self) -> Strand<'_> { match self { - Self::Borrowed(s) => s.as_strand_dyn(), - Self::Owned(s) => s.as_strand_dyn(), + Self::Os(s) => Strand::Os(s), + Self::Utf8(s) => Strand::Utf8(s), + Self::Bytes(b) => Strand::Bytes(b), } } } + +impl AsStrand for &StrandBuf { + fn as_strand(&self) -> Strand<'_> { (**self).as_strand() } +} + +impl AsStrand for StrandCow<'_> { + fn as_strand(&self) -> Strand<'_> { + match self { + StrandCow::Borrowed(s) => *s, + StrandCow::Owned(s) => s.as_strand(), + } + } +} + +impl AsStrand for &StrandCow<'_> { + fn as_strand(&self) -> Strand<'_> { (**self).as_strand() } +} diff --git a/yazi-shared/src/strand/cow.rs b/yazi-shared/src/strand/cow.rs index 7f7fb567..58b85aa1 100644 --- a/yazi-shared/src/strand/cow.rs +++ b/yazi-shared/src/strand/cow.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::{OsStr, OsString}}; use anyhow::Result; -use crate::{IntoOsStr, scheme::SchemeKind, strand::{Strand, StrandBuf, StrandBufLike, StrandLike}}; +use crate::{IntoOsStr, scheme::SchemeKind, strand::{Strand, StrandBuf}}; // --- StrandCow pub enum StrandCow<'a> { @@ -41,16 +41,6 @@ impl PartialEq> for StrandCow<'_> { } impl<'a> StrandCow<'a> { - pub fn with(kind: SchemeKind, bytes: T) -> Result - where - T: Into>, - { - match kind { - SchemeKind::Regular | SchemeKind::Search | SchemeKind::Archive => Self::from_os_bytes(bytes), - SchemeKind::Sftp => Self::from_os_bytes(bytes), // FIXME - } - } - pub fn from_os_bytes(bytes: impl Into>) -> Result { Ok(match bytes.into().into_os_str()? { Cow::Borrowed(s) => Strand::Os(s).into(), @@ -65,11 +55,13 @@ impl<'a> StrandCow<'a> { } } - // FIXME: remove, instead implement StrandLike for StrandCow - pub fn encoded_bytes(&self) -> &[u8] { - match self { - Self::Borrowed(s) => s.encoded_bytes(), - Self::Owned(s) => s.encoded_bytes(), + pub fn with(kind: SchemeKind, bytes: T) -> Result + where + T: Into>, + { + match kind { + SchemeKind::Regular | SchemeKind::Search | SchemeKind::Archive => Self::from_os_bytes(bytes), + SchemeKind::Sftp => Self::from_os_bytes(bytes), // FIXME } } } diff --git a/yazi-shared/src/strand/dyn.rs b/yazi-shared/src/strand/dyn.rs index db36d266..5512cb7a 100644 --- a/yazi-shared/src/strand/dyn.rs +++ b/yazi-shared/src/strand/dyn.rs @@ -1,8 +1,6 @@ -use std::ffi::{OsStr, OsString}; +use std::{borrow::Cow, ffi::OsStr, fmt::Display}; -use serde::Serialize; - -use crate::{FromWtf8, path::PathDyn, scheme::SchemeKind, strand::{AsStrandDyn, StrandBufLike, StrandError, StrandKind, StrandLike}}; +use crate::{BytesExt, FromWtf8, strand::{AsStrand, StrandBuf, StrandError, StrandKind}}; // --- Strand #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -44,16 +42,6 @@ impl PartialEq<&str> for Strand<'_> { } } -impl<'a> Strand<'a> { - pub fn to_owned(self) -> StrandBuf { - match self { - Self::Os(s) => StrandBuf::Os(s.to_owned()), - Self::Utf8(s) => StrandBuf::Utf8(s.to_owned()), - Self::Bytes(b) => StrandBuf::Bytes(b.to_owned()), - } - } -} - impl<'a> Strand<'a> { #[inline] pub fn as_os(self) -> Result<&'a OsStr, StrandError> { @@ -94,6 +82,38 @@ impl<'a> Strand<'a> { unsafe { StrandBuf::from_encoded_bytes(self.kind(), out) }.into() } + pub fn contains(self, x: impl AsStrand) -> bool { + memchr::memmem::find(self.encoded_bytes(), x.as_strand().encoded_bytes()).is_some() + } + + pub fn display(self) -> impl Display { + struct D<'a>(Strand<'a>); + + impl<'a> Display for D<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0 { + Strand::Os(s) => s.display().fmt(f), + Strand::Utf8(s) => s.fmt(f), + Strand::Bytes(b) => b.display().fmt(f), + } + } + } + + D(self) + } + + pub fn encoded_bytes(self) -> &'a [u8] { + match self { + Self::Os(s) => s.as_encoded_bytes(), + Self::Utf8(s) => s.as_bytes(), + Self::Bytes(b) => b, + } + } + + pub fn eq_ignore_ascii_case(self, other: impl AsStrand) -> bool { + self.encoded_bytes().eq_ignore_ascii_case(other.as_strand().encoded_bytes()) + } + #[inline] pub unsafe fn from_encoded_bytes(kind: impl Into, bytes: &'a [u8]) -> Self { match kind.into() { @@ -102,76 +122,34 @@ impl<'a> Strand<'a> { StrandKind::Bytes => Self::Bytes(bytes), } } -} -// --- StrandBuf -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] -#[serde(untagged)] -pub enum StrandBuf { - Os(OsString), - Utf8(String), - Bytes(Vec), -} + pub fn is_empty(self) -> bool { self.encoded_bytes().is_empty() } -impl Default for StrandBuf { - fn default() -> Self { Self::Utf8(String::new()) } -} - -impl From for StrandBuf { - fn from(value: OsString) -> Self { Self::Os(value) } -} - -impl From for StrandBuf { - fn from(value: String) -> Self { Self::Utf8(value) } -} - -impl From> for StrandBuf { - fn from(value: PathDyn) -> Self { - match value { - PathDyn::Os(p) => Self::Os(p.as_os_str().to_owned()), - } - } -} - -impl PartialEq> for StrandBuf { - fn eq(&self, other: &Strand<'_>) -> bool { self.borrow() == *other } -} - -impl StrandBuf { - pub fn clear(&mut self) { + pub fn kind(self) -> StrandKind { match self { - Self::Os(buf) => buf.clear(), - Self::Utf8(buf) => buf.clear(), - Self::Bytes(buf) => buf.clear(), + Self::Os(_) => StrandKind::Os, + Self::Utf8(_) => StrandKind::Utf8, + Self::Bytes(_) => StrandKind::Bytes, } } - pub fn try_push(&mut self, s: T) -> Result<(), StrandError> - where - T: AsStrandDyn, - { - let s = s.as_strand_dyn(); - Ok(match self { - Self::Os(buf) => buf.push(s.as_os()?), - Self::Utf8(buf) => buf.push_str(s.as_utf8()?), - Self::Bytes(buf) => buf.extend(s.encoded_bytes()), - }) + pub fn len(self) -> usize { self.encoded_bytes().len() } + + pub fn starts_with(self, needle: impl AsStrand) -> bool { + self.encoded_bytes().starts_with(needle.as_strand().encoded_bytes()) } - pub fn with_capacity(kind: SchemeKind, capacity: usize) -> Self { - use SchemeKind as K; - match kind { - K::Regular | K::Search | K::Archive => Self::Os(OsString::with_capacity(capacity)), - K::Sftp => Self::Os(OsString::with_capacity(capacity)), // FIXME + pub fn to_owned(self) -> StrandBuf { + match self { + Self::Os(s) => StrandBuf::Os(s.to_owned()), + Self::Utf8(s) => StrandBuf::Utf8(s.to_owned()), + Self::Bytes(b) => StrandBuf::Bytes(b.to_owned()), } } - #[inline] - pub unsafe fn from_encoded_bytes(kind: impl Into, bytes: Vec) -> Self { - match kind.into() { - StrandKind::Os => Self::Os(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }), - StrandKind::Utf8 => Self::Utf8(unsafe { String::from_utf8_unchecked(bytes) }), - StrandKind::Bytes => Self::Bytes(bytes), - } + pub fn to_str(self) -> Result<&'a str, std::str::Utf8Error> { + str::from_utf8(self.encoded_bytes()) } + + pub fn to_string_lossy(self) -> Cow<'a, str> { String::from_utf8_lossy(self.encoded_bytes()) } } diff --git a/yazi-shared/src/strand/error.rs b/yazi-shared/src/strand/error.rs index d110a229..83e521da 100644 --- a/yazi-shared/src/strand/error.rs +++ b/yazi-shared/src/strand/error.rs @@ -20,5 +20,5 @@ impl From for StrandError { } impl From for std::io::Error { - fn from(err: StrandError) -> Self { std::io::Error::other(err) } + fn from(err: StrandError) -> Self { Self::other(err) } } diff --git a/yazi-shared/src/strand/like.rs b/yazi-shared/src/strand/like.rs new file mode 100644 index 00000000..e55f5d44 --- /dev/null +++ b/yazi-shared/src/strand/like.rs @@ -0,0 +1,47 @@ +use std::{borrow::Cow, ffi::OsStr, fmt::Display}; + +use crate::strand::{AsStrand, StrandBuf, StrandCow, StrandError, StrandKind}; + +// --- StrandLike +pub trait StrandLike: AsStrand { + fn as_os(&self) -> Result<&OsStr, StrandError> { self.as_strand().as_os() } + + fn as_utf8(&self) -> Result<&str, StrandError> { self.as_strand().as_utf8() } + + #[cfg(windows)] + fn backslash_to_slash(&self) -> StrandCow<'_> { self.as_strand().backslash_to_slash() } + + fn contains(&self, x: impl AsStrand) -> bool { self.as_strand().contains(x) } + + fn display(&self) -> impl Display { self.as_strand().display() } + + fn encoded_bytes(&self) -> &[u8] { self.as_strand().encoded_bytes() } + + fn eq_ignore_ascii_case(&self, other: impl AsStrand) -> bool { + self.as_strand().eq_ignore_ascii_case(other) + } + + fn is_empty(&self) -> bool { self.as_strand().is_empty() } + + fn kind(&self) -> StrandKind { self.as_strand().kind() } + + fn len(&self) -> usize { self.as_strand().len() } + + fn starts_with(&self, needle: impl AsStrand) -> bool { self.as_strand().starts_with(needle) } + + fn to_owned(&self) -> StrandBuf { self.as_strand().to_owned() } + + fn to_str(&self) -> Result<&str, std::str::Utf8Error> { self.as_strand().to_str() } + + fn to_string_lossy(&self) -> Cow<'_, str> { self.as_strand().to_string_lossy() } +} + +impl From<&S> for StrandBuf +where + S: StrandLike, +{ + fn from(value: &S) -> Self { value.to_owned() } +} + +impl StrandLike for StrandBuf {} +impl StrandLike for StrandCow<'_> {} diff --git a/yazi-shared/src/strand/mod.rs b/yazi-shared/src/strand/mod.rs index 25180bc2..ca1ffd07 100644 --- a/yazi-shared/src/strand/mod.rs +++ b/yazi-shared/src/strand/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(conversion cow error kind r#dyn strand view); +yazi_macro::mod_flat!(buf conversion cow error kind like r#dyn view); diff --git a/yazi-shared/src/strand/strand.rs b/yazi-shared/src/strand/strand.rs deleted file mode 100644 index a3a1dc3e..00000000 --- a/yazi-shared/src/strand/strand.rs +++ /dev/null @@ -1,168 +0,0 @@ -use std::{borrow::Cow, ffi::{OsStr, OsString}, fmt::Display}; - -use crate::{BytesExt, strand::{AsStrand, Strand, StrandBuf, StrandKind}}; - -// --- StrandLike -pub trait StrandLike<'a>: Copy { - type Owned: StrandBufLike; - - fn contains(self, x: impl AsStrand) -> bool { - memchr::memmem::find(self.encoded_bytes(), x.as_strand().encoded_bytes()).is_some() - } - - fn display(self) -> impl Display; - - fn encoded_bytes(self) -> &'a [u8]; - - fn is_empty(self) -> bool { self.encoded_bytes().is_empty() } - - fn kind(self) -> StrandKind; - - fn len(self) -> usize { self.encoded_bytes().len() } - - fn to_str(self) -> Result<&'a str, std::str::Utf8Error> { str::from_utf8(self.encoded_bytes()) } - - fn to_string_lossy(self) -> Cow<'a, str> { String::from_utf8_lossy(self.encoded_bytes()) } - - fn eq_ignore_ascii_case(self, other: impl AsStrand) -> bool { - self.encoded_bytes().eq_ignore_ascii_case(other.as_strand().encoded_bytes()) - } - - fn starts_with(self, needle: impl AsStrand) -> bool { - self.encoded_bytes().starts_with(needle.as_strand().encoded_bytes()) - } -} - -impl<'a> StrandLike<'a> for &'a [u8] { - type Owned = Vec; - - fn display(self) -> impl Display { BytesExt::display(self) } - - fn encoded_bytes(self) -> &'a [u8] { self } - - fn kind(self) -> StrandKind { StrandKind::Bytes } -} - -impl<'a> StrandLike<'a> for &'a str { - type Owned = String; - - fn display(self) -> impl Display { self } - - fn encoded_bytes(self) -> &'a [u8] { self.as_bytes() } - - fn kind(self) -> StrandKind { StrandKind::Utf8 } -} - -impl<'a> StrandLike<'a> for &'a OsStr { - type Owned = OsString; - - fn display(self) -> impl Display { self.display() } - - fn encoded_bytes(self) -> &'a [u8] { self.as_encoded_bytes() } - - fn kind(self) -> StrandKind { StrandKind::Os } -} - -impl<'a> StrandLike<'a> for Strand<'a> { - type Owned = StrandBuf; - - fn display(self) -> impl Display { - struct D<'a>(Strand<'a>); - - impl<'a> Display for D<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.0 { - Strand::Os(s) => s.display().fmt(f), - Strand::Utf8(s) => s.fmt(f), - Strand::Bytes(b) => BytesExt::display(b).fmt(f), - } - } - } - - D(self) - } - - fn encoded_bytes(self) -> &'a [u8] { - match self { - Self::Os(s) => s.as_encoded_bytes(), - Self::Utf8(s) => s.as_bytes(), - Self::Bytes(b) => b, - } - } - - fn kind(self) -> StrandKind { - match self { - Self::Os(_) => StrandKind::Os, - Self::Utf8(_) => StrandKind::Utf8, - Self::Bytes(_) => StrandKind::Bytes, - } - } -} - -// --- StrandBufLike -pub trait StrandBufLike -where - Self: 'static + AsStrand, -{ - type Borrowed<'a>: StrandLike<'a>; - - fn borrow(&self) -> Self::Borrowed<'_>; - - fn encoded_bytes(&self) -> &[u8] { self.borrow().encoded_bytes() } - - fn into_encoded_bytes(self) -> Vec; - - fn is_empty(&self) -> bool { self.borrow().is_empty() } - - fn kind(&self) -> StrandKind { self.borrow().kind() } - - fn len(&self) -> usize { self.borrow().len() } - - fn to_str(&self) -> Result<&str, std::str::Utf8Error> { self.borrow().to_str() } - - fn to_string_lossy(&self) -> Cow<'_, str> { self.borrow().to_string_lossy() } -} - -impl StrandBufLike for Vec { - type Borrowed<'a> = &'a [u8]; - - fn borrow(&self) -> Self::Borrowed<'_> { self.as_slice() } - - fn into_encoded_bytes(self) -> Vec { self } -} - -impl StrandBufLike for String { - type Borrowed<'a> = &'a str; - - fn borrow(&self) -> Self::Borrowed<'_> { self.as_str() } - - fn into_encoded_bytes(self) -> Vec { self.into_bytes() } -} - -impl StrandBufLike for OsString { - type Borrowed<'a> = &'a OsStr; - - fn borrow(&self) -> Self::Borrowed<'_> { self.as_os_str() } - - fn into_encoded_bytes(self) -> Vec { self.into_encoded_bytes() } -} - -impl StrandBufLike for StrandBuf { - type Borrowed<'a> = Strand<'a>; - - fn borrow(&self) -> Self::Borrowed<'_> { - match self { - Self::Os(s) => Strand::Os(s.as_os_str()), - Self::Utf8(s) => Strand::Utf8(s.as_str()), - Self::Bytes(b) => Strand::Bytes(b), - } - } - - fn into_encoded_bytes(self) -> Vec { - match self { - Self::Os(s) => s.into_encoded_bytes(), - Self::Utf8(s) => s.into_bytes(), - Self::Bytes(b) => b, - } - } -} diff --git a/yazi-shared/src/strand/view.rs b/yazi-shared/src/strand/view.rs index d29d687a..454f713b 100644 --- a/yazi-shared/src/strand/view.rs +++ b/yazi-shared/src/strand/view.rs @@ -1,6 +1,6 @@ use std::ffi::OsStr; -use crate::{path::PathDyn, strand::{AsStrandDyn, Strand}}; +use crate::{path::PathDyn, strand::Strand}; // --- AsStrandView pub trait AsStrandView<'a, T> { @@ -42,10 +42,3 @@ impl<'a> AsStrandView<'a, Strand<'a>> for PathDyn<'a> { } } } - -impl<'a, T> AsStrandView<'a, Strand<'a>> for &'a T -where - T: AsStrandDyn, -{ - fn as_strand_view(self) -> Strand<'a> { self.as_strand_dyn() } -} diff --git a/yazi-shared/src/url/buf.rs b/yazi-shared/src/url/buf.rs index 8f346907..4206a177 100644 --- a/yazi-shared/src/url/buf.rs +++ b/yazi-shared/src/url/buf.rs @@ -3,7 +3,7 @@ use std::{borrow::Cow, fmt::{Debug, Formatter}, path::{Path, PathBuf}, str::From use anyhow::Result; use serde::{Deserialize, Serialize}; -use crate::{loc::LocBuf, path::{PathBufDyn, PathBufDynError, PathDyn, PathDynError, PathLike, SetNameError}, pool::{InternStr, Pool, Symbol}, scheme::SchemeKind, strand::AsStrandDyn, url::{AsUrl, Url, UrlCow, UrlLike}}; +use crate::{loc::LocBuf, path::{PathBufDyn, PathBufDynError, PathDyn, PathDynError, SetNameError}, pool::{InternStr, Pool, Symbol}, scheme::SchemeKind, strand::AsStrand, url::{AsUrl, Url, UrlCow, UrlLike}}; #[derive(Clone, Eq, Hash, PartialEq)] pub enum UrlBuf { @@ -18,8 +18,8 @@ impl Default for UrlBuf { fn default() -> Self { Self::Regular(Default::default()) } } -impl From<&UrlBuf> for UrlBuf { - fn from(url: &UrlBuf) -> Self { url.clone() } +impl From<&Self> for UrlBuf { + fn from(url: &Self) -> Self { url.clone() } } impl From> for UrlBuf { @@ -110,10 +110,10 @@ impl UrlBuf { #[inline] pub fn into_loc(self) -> PathBufDyn { match self { - Self::Regular(loc) => loc.into_path().into(), - Self::Search { loc, .. } => loc.into_path().into(), - Self::Archive { loc, .. } => loc.into_path().into(), - Self::Sftp { loc, .. } => loc.into_path().into(), + Self::Regular(loc) => loc.into_inner().into(), + Self::Search { loc, .. } => loc.into_inner().into(), + Self::Archive { loc, .. } => loc.into_inner().into(), + Self::Sftp { loc, .. } => loc.into_inner().into(), } } @@ -122,8 +122,8 @@ impl UrlBuf { if self.kind().is_local() { self.into_loc().into_os().ok() } else { None } } - pub fn try_set_name(&mut self, name: impl AsStrandDyn) -> Result<(), SetNameError> { - let name = name.as_strand_dyn(); + pub fn try_set_name(&mut self, name: impl AsStrand) -> Result<(), SetNameError> { + let name = name.as_strand(); Ok(match self { Self::Regular(loc) => loc.try_set_name(name.as_os()?)?, Self::Search { loc, .. } => loc.try_set_name(name.as_os()?)?, @@ -132,19 +132,17 @@ impl UrlBuf { }) } - pub fn rebase(&self, base: &Path) -> Result { - Ok(match self { - Self::Regular(loc) => Self::Regular(loc.rebase(base)?), + pub fn rebase(&self, base: &Path) -> Self { + match self { + Self::Regular(loc) => Self::Regular(loc.rebase(base)), Self::Search { loc, domain } => { - Self::Search { loc: loc.rebase(base)?, domain: domain.clone() } + Self::Search { loc: loc.rebase(base), domain: domain.clone() } } Self::Archive { loc, domain } => { - Self::Archive { loc: loc.rebase(base)?, domain: domain.clone() } + Self::Archive { loc: loc.rebase(base), domain: domain.clone() } } - Self::Sftp { loc, domain } => { - Self::Sftp { loc: loc.rebase(base)?, domain: domain.clone() } - } - }) + Self::Sftp { loc, domain } => Self::Sftp { loc: loc.rebase(base), domain: domain.clone() }, + } } } @@ -275,8 +273,10 @@ mod tests { ("archive://:1:1//a/b.zip/c", Some("archive:////a/b.zip")), ("archive:////a/b.zip", Some("/a")), // SFTP - ("sftp://remote:1:1//a/b", Some("sftp://remote//a")), + ("sftp://remote:3:1//a/b", Some("sftp://remote//a")), + ("sftp://remote:2:1//a", Some("sftp://remote//")), ("sftp://remote:1:1//a", Some("sftp://remote//")), + ("sftp://remote//a", Some("sftp://remote//")), ("sftp://remote:1//", None), ("sftp://remote//", None), // Relative diff --git a/yazi-shared/src/url/component.rs b/yazi-shared/src/url/component.rs index f7670adb..fdba0425 100644 --- a/yazi-shared/src/url/component.rs +++ b/yazi-shared/src/url/component.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::{OsStr, OsString}, iter::FusedIterator, ops::Not, pa use anyhow::Result; -use crate::{path::{PathBufDyn, PathCow, PathLike}, scheme::SchemeRef, url::{Encode, Url, UrlBuf, UrlCow}}; +use crate::{path::{PathBufDyn, PathCow}, scheme::SchemeRef, url::{Encode, Url, UrlBuf, UrlCow}}; #[derive(Clone, Copy, Debug, PartialEq)] pub enum Component<'a> { diff --git a/yazi-shared/src/url/display.rs b/yazi-shared/src/url/display.rs index 020402a4..176600b6 100644 --- a/yazi-shared/src/url/display.rs +++ b/yazi-shared/src/url/display.rs @@ -1,4 +1,4 @@ -use crate::{path::PathLike, scheme::Encode, url::Url}; +use crate::{scheme::Encode, url::Url}; pub struct Display<'a> { inner: Url<'a>, diff --git a/yazi-shared/src/url/encode.rs b/yazi-shared/src/url/encode.rs index a857ea40..fe2a9d3f 100644 --- a/yazi-shared/src/url/encode.rs +++ b/yazi-shared/src/url/encode.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display}; use percent_encoding::{CONTROLS, percent_encode}; -use crate::{path::PathLike, url::Url}; +use crate::url::Url; // --- Tilded #[derive(Clone, Copy)] diff --git a/yazi-shared/src/url/traits.rs b/yazi-shared/src/url/traits.rs index b8b8aacc..717cb0b7 100644 --- a/yazi-shared/src/url/traits.rs +++ b/yazi-shared/src/url/traits.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsStr, path::{Path, PathBuf}}; use anyhow::Result; -use crate::{loc::Loc, path::{AsPathRef, EndsWithError, JoinError, PathDyn, StartsWithError, StripPrefixError}, scheme::{SchemeKind, SchemeRef}, strand::{AsStrandDyn, Strand}, url::{Components, Display, Url, UrlBuf, UrlCow}}; +use crate::{loc::Loc, path::{AsPathRef, EndsWithError, JoinError, PathDyn, StartsWithError, StripPrefixError}, scheme::{SchemeKind, SchemeRef}, strand::{AsStrand, Strand}, url::{Components, Display, Url, UrlBuf, UrlCow}}; // --- AsUrl pub trait AsUrl { @@ -103,7 +103,7 @@ where // UrlLike pub trait UrlLike where - Self: AsUrl + Sized, + Self: AsUrl, { fn as_local(&self) -> Option<&Path> { self.as_url().as_local() } @@ -147,7 +147,7 @@ where self.as_url().try_ends_with(child) } - fn try_join(&self, path: impl AsStrandDyn) -> Result { + fn try_join(&self, path: impl AsStrand) -> Result { self.as_url().try_join(path) } diff --git a/yazi-shared/src/url/url.rs b/yazi-shared/src/url/url.rs index 71f67e84..d0e86fbb 100644 --- a/yazi-shared/src/url/url.rs +++ b/yazi-shared/src/url/url.rs @@ -5,7 +5,7 @@ use hashbrown::Equivalent; use serde::Serialize; use super::Encode as EncodeUrl; -use crate::{loc::{Loc, LocBuf}, path::{AsPathDyn, AsPathRef, EndsWithError, JoinError, PathBufDyn, PathBufLike, PathDyn, PathDynError, PathLike, StartsWithError, StripPrefixError}, pool::InternStr, scheme::{Encode as EncodeScheme, SchemeCow, SchemeKind, SchemeRef}, strand::{AsStrandDyn, Strand}, url::{AsUrl, Components, UrlBuf, UrlCow}}; +use crate::{loc::{Loc, LocBuf}, path::{AsPath, AsPathRef, EndsWithError, JoinError, PathBufDyn, PathDyn, PathDynError, PathLike, StartsWithError, StripPrefixError}, pool::InternStr, scheme::{Encode as EncodeScheme, SchemeCow, SchemeKind, SchemeRef}, strand::{AsStrand, Strand}, url::{AsUrl, Components, UrlBuf, UrlCow}}; #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub enum Url<'a> { @@ -58,14 +58,13 @@ impl<'a> Url<'a> { } } - // FIXME: add to UrlLike trait #[inline] pub fn loc(self) -> PathDyn<'a> { match self { - Self::Regular(loc) => loc.as_path_dyn(), - Self::Search { loc, .. } => loc.as_path_dyn(), - Self::Archive { loc, .. } => loc.as_path_dyn(), - Self::Sftp { loc, .. } => loc.as_path_dyn(), + Self::Regular(loc) => loc.as_path(), + Self::Search { loc, .. } => loc.as_path(), + Self::Archive { loc, .. } => loc.as_path(), + Self::Sftp { loc, .. } => loc.as_path(), } } @@ -105,8 +104,8 @@ impl<'a> Url<'a> { #[inline] pub fn to_owned(self) -> UrlBuf { self.into() } - pub fn try_join(self, path: impl AsStrandDyn) -> Result { - let joined = self.loc().try_join(&path)?; + pub fn try_join(self, path: impl AsStrand) -> Result { + let joined = self.loc().try_join(path)?; Ok(match self { Self::Regular(_) => UrlBuf::Regular(joined.into_os()?.into()), @@ -177,7 +176,7 @@ impl<'a> Url<'a> { use Url as U; let base = base.as_url(); - let prefix = self.loc().try_strip_prefix(base.loc())?.into(); + let prefix = self.loc().try_strip_prefix(base.loc())?; match (self, base) { // Same scheme @@ -221,50 +220,50 @@ impl<'a> Url<'a> { #[inline] pub fn uri(self) -> PathDyn<'a> { match self { - Self::Regular(loc) => loc.uri().as_path_dyn(), - Self::Search { loc, .. } => loc.uri().as_path_dyn(), - Self::Archive { loc, .. } => loc.uri().as_path_dyn(), - Self::Sftp { loc, .. } => loc.uri().as_path_dyn(), + Self::Regular(loc) => loc.uri().as_path(), + Self::Search { loc, .. } => loc.uri().as_path(), + Self::Archive { loc, .. } => loc.uri().as_path(), + Self::Sftp { loc, .. } => loc.uri().as_path(), } } #[inline] pub fn urn(self) -> PathDyn<'a> { match self { - Self::Regular(loc) => loc.urn().as_path_dyn(), - Self::Search { loc, .. } => loc.urn().as_path_dyn(), - Self::Archive { loc, .. } => loc.urn().as_path_dyn(), - Self::Sftp { loc, .. } => loc.urn().as_path_dyn(), + Self::Regular(loc) => loc.urn().as_path(), + Self::Search { loc, .. } => loc.urn().as_path(), + Self::Archive { loc, .. } => loc.urn().as_path(), + Self::Sftp { loc, .. } => loc.urn().as_path(), } } #[inline] pub fn name(self) -> Option> { Some(match self { - Self::Regular(loc) => loc.name()?.as_strand_dyn(), - Self::Search { loc, .. } => loc.name()?.as_strand_dyn(), - Self::Archive { loc, .. } => loc.name()?.as_strand_dyn(), - Self::Sftp { loc, .. } => loc.name()?.as_strand_dyn(), + Self::Regular(loc) => loc.file_name()?.as_strand(), + Self::Search { loc, .. } => loc.file_name()?.as_strand(), + Self::Archive { loc, .. } => loc.file_name()?.as_strand(), + Self::Sftp { loc, .. } => loc.file_name()?.as_strand(), }) } #[inline] pub fn stem(self) -> Option> { Some(match self { - Self::Regular(loc) => loc.stem()?.as_strand_dyn(), - Self::Search { loc, .. } => loc.stem()?.as_strand_dyn(), - Self::Archive { loc, .. } => loc.stem()?.as_strand_dyn(), - Self::Sftp { loc, .. } => loc.stem()?.as_strand_dyn(), + Self::Regular(loc) => loc.file_stem()?.as_strand(), + Self::Search { loc, .. } => loc.file_stem()?.as_strand(), + Self::Archive { loc, .. } => loc.file_stem()?.as_strand(), + Self::Sftp { loc, .. } => loc.file_stem()?.as_strand(), }) } #[inline] pub fn ext(self) -> Option> { Some(match self { - Self::Regular(loc) => loc.ext()?.as_strand_dyn(), - Self::Search { loc, .. } => loc.ext()?.as_strand_dyn(), - Self::Archive { loc, .. } => loc.ext()?.as_strand_dyn(), - Self::Sftp { loc, .. } => loc.ext()?.as_strand_dyn(), + Self::Regular(loc) => loc.extension()?.as_strand(), + Self::Search { loc, .. } => loc.extension()?.as_strand(), + Self::Archive { loc, .. } => loc.extension()?.as_strand(), + Self::Sftp { loc, .. } => loc.extension()?.as_strand(), }) } @@ -291,11 +290,11 @@ impl<'a> Url<'a> { match self { Self::Regular(loc) | Self::Search { loc, .. } | Self::Archive { loc, .. } => { let (base, rest, urn) = loc.triple(); - (base.as_path_dyn(), rest.as_path_dyn(), urn.as_path_dyn()) + (base.as_path(), rest.as_path(), urn.as_path()) } Self::Sftp { loc, .. } => { let (base, rest, urn) = loc.triple(); - (base.as_path_dyn(), rest.as_path_dyn(), urn.as_path_dyn()) + (base.as_path(), rest.as_path(), urn.as_path()) } } } diff --git a/yazi-shared/src/wtf8.rs b/yazi-shared/src/wtf8.rs index 4364f80a..cf785aba 100644 --- a/yazi-shared/src/wtf8.rs +++ b/yazi-shared/src/wtf8.rs @@ -31,12 +31,12 @@ impl FromWtf8 for OsStr { #[cfg(unix)] { use std::os::unix::ffi::OsStrExt; - Ok(OsStr::from_bytes(wtf8)) + Ok(Self::from_bytes(wtf8)) } #[cfg(windows)] { // FIXME: validate WTF-8 - Ok(unsafe { OsStr::from_encoded_bytes_unchecked(wtf8) }) + Ok(unsafe { Self::from_encoded_bytes_unchecked(wtf8) }) } } } @@ -57,12 +57,12 @@ impl FromWtf8Vec for OsString { #[cfg(unix)] { use std::os::unix::ffi::OsStringExt; - Ok(OsString::from_vec(wtf8)) + Ok(Self::from_vec(wtf8)) } #[cfg(windows)] { // FIXME: validate WTF-8 - Ok(unsafe { OsString::from_encoded_bytes_unchecked(wtf8) }) + Ok(unsafe { Self::from_encoded_bytes_unchecked(wtf8) }) } } } diff --git a/yazi-shim/Cargo.toml b/yazi-shim/Cargo.toml index 069ae5c2..6933f1ab 100644 --- a/yazi-shim/Cargo.toml +++ b/yazi-shim/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi crate shims" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-macro = { path = "../yazi-macro", version = "25.9.15" } diff --git a/yazi-term/Cargo.toml b/yazi-term/Cargo.toml index a75c8946..d522deb5 100644 --- a/yazi-term/Cargo.toml +++ b/yazi-term/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi terminal extensions" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-macro = { path = "../yazi-macro", version = "25.9.15" } yazi-shared = { path = "../yazi-shared", version = "25.9.15" } diff --git a/yazi-term/src/background.rs b/yazi-term/src/background.rs index de20c482..0ec18df7 100644 --- a/yazi-term/src/background.rs +++ b/yazi-term/src/background.rs @@ -3,7 +3,7 @@ pub struct SetBackground(pub bool, pub String); impl crossterm::Command for SetBackground { fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result { if self.1.is_empty() { - return Ok(()); + Ok(()) } else if self.0 { write!(f, "\x1b]11;{}\x1b\\", self.1) } else { diff --git a/yazi-vfs/Cargo.toml b/yazi-vfs/Cargo.toml index 4e755ae8..3bed8acd 100644 --- a/yazi-vfs/Cargo.toml +++ b/yazi-vfs/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi virtual file system" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-config = { path = "../yazi-config", version = "25.9.15" } yazi-fs = { path = "../yazi-fs", version = "25.9.15" } diff --git a/yazi-vfs/src/fns.rs b/yazi-vfs/src/fns.rs index 5bf08c25..25115c72 100644 --- a/yazi-vfs/src/fns.rs +++ b/yazi-vfs/src/fns.rs @@ -3,7 +3,7 @@ use std::io; use tokio::{select, sync::{mpsc, oneshot}}; use yazi_fs::provider::Attrs; use yazi_macro::ok_or_not_found; -use yazi_shared::{strand::{StrandBuf, StrandBufLike, StrandLike}, url::{AsUrl, Url, UrlBuf, UrlLike}}; +use yazi_shared::{strand::{StrandBuf, StrandLike}, url::{AsUrl, Url, UrlBuf, UrlLike}}; use crate::provider; @@ -91,7 +91,7 @@ fn _copy_with_progress(from: Url, to: Url, attrs: Attrs) -> mpsc::Receiver(original: P, link: U) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, U: AsUrl, { Providers::new(link.as_url()).await?.symlink_dir(original).await @@ -207,7 +207,7 @@ where pub async fn symlink_file(original: P, link: U) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, U: AsUrl, { Providers::new(link.as_url()).await?.symlink_file(original).await diff --git a/yazi-vfs/src/provider/providers.rs b/yazi-vfs/src/provider/providers.rs index e2065160..d0ec7f90 100644 --- a/yazi-vfs/src/provider/providers.rs +++ b/yazi-vfs/src/provider/providers.rs @@ -1,7 +1,7 @@ use std::io; use yazi_fs::{cha::Cha, provider::{Attrs, Provider}}; -use yazi_shared::{path::{AsPathDyn, PathBufDyn}, url::{Url, UrlBuf, UrlCow}}; +use yazi_shared::{path::{AsPath, PathBufDyn}, url::{Url, UrlBuf, UrlCow}}; #[derive(Clone)] pub(super) enum Providers<'a> { @@ -39,7 +39,7 @@ impl<'a> Provider for Providers<'a> { async fn copy

(&self, to: P, attrs: Attrs) -> io::Result where - P: AsPathDyn, + P: AsPath, { match self { Self::Local(p) => p.copy(to, attrs).await, @@ -70,7 +70,7 @@ impl<'a> Provider for Providers<'a> { async fn hard_link

(&self, to: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { match self { Self::Local(p) => p.hard_link(to).await, @@ -141,7 +141,7 @@ impl<'a> Provider for Providers<'a> { async fn rename

(&self, to: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { match self { Self::Local(p) => p.rename(to).await, @@ -151,7 +151,7 @@ impl<'a> Provider for Providers<'a> { async fn symlink(&self, original: P, is_dir: F) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, F: AsyncFnOnce() -> io::Result, { match self { @@ -162,7 +162,7 @@ impl<'a> Provider for Providers<'a> { async fn symlink_dir

(&self, original: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { match self { Self::Local(p) => p.symlink_dir(original).await, @@ -172,7 +172,7 @@ impl<'a> Provider for Providers<'a> { async fn symlink_file

(&self, original: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { match self { Self::Local(p) => p.symlink_file(original).await, diff --git a/yazi-vfs/src/provider/sftp/gate.rs b/yazi-vfs/src/provider/sftp/gate.rs index 795c41b4..4585b531 100644 --- a/yazi-vfs/src/provider/sftp/gate.rs +++ b/yazi-vfs/src/provider/sftp/gate.rs @@ -12,24 +12,24 @@ pub struct Gate(crate::provider::Gate); impl From for Flags { fn from(Gate(g): Gate) -> Self { - let mut flags = Flags::empty(); + let mut flags = Self::empty(); if g.append { - flags |= Flags::APPEND; + flags |= Self::APPEND; } if g.create { - flags |= Flags::CREATE; + flags |= Self::CREATE; } if g.create_new { - flags |= Flags::CREATE | Flags::EXCLUDE; + flags |= Self::CREATE | Self::EXCLUDE; } if g.read { - flags |= Flags::READ; + flags |= Self::READ; } if g.truncate { - flags |= Flags::TRUNCATE; + flags |= Self::TRUNCATE; } if g.write { - flags |= Flags::WRITE; + flags |= Self::WRITE; } flags } diff --git a/yazi-vfs/src/provider/sftp/metadata.rs b/yazi-vfs/src/provider/sftp/metadata.rs index 5e2282a1..23c2ee9e 100644 --- a/yazi-vfs/src/provider/sftp/metadata.rs +++ b/yazi-vfs/src/provider/sftp/metadata.rs @@ -39,7 +39,7 @@ impl TryFrom<(&OsStr, &yazi_sftp::fs::Attrs)> for Cha { let kind = if name.as_encoded_bytes().starts_with(b".") { ChaKind::HIDDEN } else { ChaKind::empty() }; - Ok(Cha(yazi_fs::cha::Cha { + Ok(Self(yazi_fs::cha::Cha { kind, mode: ChaMode::try_from(attrs)?.0, len: attrs.size.unwrap_or(0), diff --git a/yazi-vfs/src/provider/sftp/sftp.rs b/yazi-vfs/src/provider/sftp/sftp.rs index b521dfe6..6bb37475 100644 --- a/yazi-vfs/src/provider/sftp/sftp.rs +++ b/yazi-vfs/src/provider/sftp/sftp.rs @@ -4,7 +4,7 @@ use tokio::io::{AsyncWriteExt, BufReader, BufWriter}; use yazi_config::vfs::{ProviderSftp, Vfs}; use yazi_fs::provider::{DirReader, FileHolder, Provider}; use yazi_sftp::fs::{Attrs, Flags}; -use yazi_shared::{path::{AsPathDyn, PathBufDyn}, pool::InternStr, strand::StrandLike, url::{Url, UrlBuf, UrlCow, UrlLike}}; +use yazi_shared::{path::{AsPath, PathBufDyn}, pool::InternStr, url::{Url, UrlBuf, UrlCow, UrlLike}}; use super::Cha; use crate::provider::sftp::Conn; @@ -69,9 +69,9 @@ impl<'a> Provider for Sftp<'a> { async fn copy

(&self, to: P, attrs: yazi_fs::provider::Attrs) -> io::Result where - P: AsPathDyn, + P: AsPath, { - let to = to.as_path_dyn().as_os()?; + let to = to.as_path().as_os()?; let attrs = Attrs::from(super::Attrs(attrs)); let op = self.op().await?; @@ -94,9 +94,9 @@ impl<'a> Provider for Sftp<'a> { async fn hard_link

(&self, to: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { - let to = to.as_path_dyn().as_os()?; + let to = to.as_path().as_os()?; Ok(self.op().await?.hardlink(self.path, to).await?) } @@ -113,7 +113,7 @@ impl<'a> Provider for Sftp<'a> { } Url::Sftp { loc, domain } => { let (name, config) = Vfs::provider::<&ProviderSftp>(domain).await?; - Ok(Self::Me { url, path: loc.as_path(), name, config }) + Ok(Self::Me { url, path: loc.as_inner(), name, config }) } } } @@ -135,9 +135,9 @@ impl<'a> Provider for Sftp<'a> { async fn rename

(&self, to: P) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, { - let to = to.as_path_dyn().as_os()?; + let to = to.as_path().as_os()?; let op = self.op().await?; match op.rename_posix(self.path, &to).await { @@ -153,10 +153,10 @@ impl<'a> Provider for Sftp<'a> { async fn symlink(&self, original: P, _is_dir: F) -> io::Result<()> where - P: AsPathDyn, + P: AsPath, F: AsyncFnOnce() -> io::Result, { - let original = original.as_path_dyn().as_os()?; + let original = original.as_path().as_os()?; Ok(self.op().await?.symlink(&original, self.path).await?) } diff --git a/yazi-watcher/Cargo.toml b/yazi-watcher/Cargo.toml index 00a6aa2b..ed9af0ba 100644 --- a/yazi-watcher/Cargo.toml +++ b/yazi-watcher/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi file watcher" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-adapter = { path = "../yazi-adapter", version = "25.9.15" } yazi-dds = { path = "../yazi-dds", version = "25.9.15" } diff --git a/yazi-watcher/src/local/local.rs b/yazi-watcher/src/local/local.rs index 67896007..2c317c3c 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::{path::PathLike, url::{UrlBuf, UrlLike}}; +use yazi_shared::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.owned()].into())); + ops.push(FilesOp::Deleting(parent.into(), [urn.into()].into())); continue; }; if let Some(p) = file.url.as_local() && !provider::local::must_case_match(p).await { - ops.push(FilesOp::Deleting(parent.into(), [urn.owned()].into())); + ops.push(FilesOp::Deleting(parent.into(), [urn.into()].into())); continue; } - ops.push(FilesOp::Upserting(parent.into(), [(urn.owned(), file)].into())); + ops.push(FilesOp::Upserting(parent.into(), [(urn.into(), file)].into())); } FilesOp::mutate(ops); diff --git a/yazi-watcher/src/remote/remote.rs b/yazi-watcher/src/remote/remote.rs index 55269834..dde45220 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::{path::PathLike, url::{Url, UrlBuf, UrlLike}}; +use yazi_shared::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.owned()].into())); + ops.push(FilesOp::Deleting(parent.into(), [urn.into()].into())); continue; }; let is_file = file.is_file(); file.cha.ctime = Some(SystemTime::now()); - ops.push(FilesOp::Upserting(parent.into(), [(urn.owned(), file)].into())); + ops.push(FilesOp::Upserting(parent.into(), [(urn.into(), file)].into())); if is_file { ups.push(u); } diff --git a/yazi-watcher/src/reporter.rs b/yazi-watcher/src/reporter.rs index 9fc16c0f..5b2f4ac0 100644 --- a/yazi-watcher/src/reporter.rs +++ b/yazi-watcher/src/reporter.rs @@ -1,5 +1,5 @@ use tokio::sync::mpsc; -use yazi_shared::{path::PathLike, scheme::SchemeKind, url::{AsUrl, Url, UrlBuf, UrlCow, UrlLike}}; +use yazi_shared::{scheme::SchemeKind, url::{AsUrl, Url, UrlBuf, UrlCow, UrlLike}}; use crate::{WATCHED, local::LINKED}; diff --git a/yazi-widgets/Cargo.toml b/yazi-widgets/Cargo.toml index 815eb3c0..b7909ba5 100644 --- a/yazi-widgets/Cargo.toml +++ b/yazi-widgets/Cargo.toml @@ -8,6 +8,9 @@ description = "Yazi user interface widgets" homepage = "https://yazi-rs.github.io" repository = "https://github.com/sxyazi/yazi" +[lints] +workspace = true + [dependencies] yazi-binding = { path = "../yazi-binding", version = "25.9.15" } yazi-config = { path = "../yazi-config", version = "25.9.15" }