mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
refactor: refine PathLike and StrandLike traits
This commit is contained in:
parent
f9abe886cc
commit
2b79c3d30f
109 changed files with 1282 additions and 1492 deletions
13
Cargo.toml
13
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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Data> {
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -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!();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
|
|
|||
|
|
@ -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!();
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ impl Actor for UpdateFiles {
|
|||
|
||||
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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" ]
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
|
|
|
|||
|
|
@ -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<String>) -> 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,
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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<T>(&self, folder: &Folder, urn: T) -> Option<u8>
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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" ]
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ impl ChaKind {
|
|||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use yazi_shared::strand::StrandLike;
|
||||
if _name.as_strand().starts_with(".") {
|
||||
me |= Self::HIDDEN;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ impl From<ChaMode> 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 _)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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<Self> {
|
||||
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<Strand<'_>> { self.url.stem() }
|
||||
|
||||
pub fn link_to_url(&self) -> Option<Url<'_>> {
|
||||
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()?)),
|
||||
|
|
|
|||
|
|
@ -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<PathBufDyn>) -> Vec<usize> {
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<Self> {
|
||||
pub fn chdir(&self, wd: &Path) -> Self {
|
||||
macro_rules! files {
|
||||
($files:expr) => {{ $files.iter().map(|file| file.chdir(wd)).collect::<Result<_>>()? }};
|
||||
($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::<Result<_>>()?
|
||||
}};
|
||||
($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<UrlBuf>, Vec<UrlBuf>) {
|
||||
|
|
|
|||
|
|
@ -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<UrlCow<'a>>) -> UrlBuf {
|
||||
let cow: UrlCow = url.into();
|
||||
|
|
|
|||
|
|
@ -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::<PathBuf>::with(
|
||||
|
|
@ -77,7 +72,7 @@ pub fn absolute_url<'a>(url: impl Into<UrlCow<'a>>) -> 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");
|
||||
|
|
|
|||
|
|
@ -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<P>(&self, to: P, attrs: Attrs) -> io::Result<u64>
|
||||
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<P>(&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<Self::Me<'b>> {
|
||||
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<P>(&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<P, F>(&self, original: P, _is_dir: F) -> io::Result<()>
|
||||
where
|
||||
P: AsPathDyn,
|
||||
P: AsPath,
|
||||
F: AsyncFnOnce() -> io::Result<bool>,
|
||||
{
|
||||
#[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<P>(&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<P>(&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)]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<P>(&self, to: P, attrs: Attrs) -> impl Future<Output = io::Result<u64>>
|
||||
where
|
||||
P: AsPathDyn;
|
||||
P: AsPath;
|
||||
|
||||
fn create(&self) -> impl Future<Output = io::Result<Self::File>> {
|
||||
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<P>(&self, to: P) -> impl Future<Output = io::Result<()>>
|
||||
where
|
||||
P: AsPathDyn;
|
||||
P: AsPath;
|
||||
|
||||
fn metadata(&self) -> impl Future<Output = io::Result<Cha>>;
|
||||
|
||||
|
|
@ -144,23 +144,23 @@ pub trait Provider: Sized {
|
|||
|
||||
fn rename<P>(&self, to: P) -> impl Future<Output = io::Result<()>>
|
||||
where
|
||||
P: AsPathDyn;
|
||||
P: AsPath;
|
||||
|
||||
fn symlink<P, F>(&self, original: P, _is_dir: F) -> impl Future<Output = io::Result<()>>
|
||||
where
|
||||
P: AsPathDyn,
|
||||
P: AsPath,
|
||||
F: AsyncFnOnce() -> io::Result<bool>;
|
||||
|
||||
fn symlink_dir<P>(&self, original: P) -> impl Future<Output = io::Result<()>>
|
||||
where
|
||||
P: AsPathDyn,
|
||||
P: AsPath,
|
||||
{
|
||||
self.symlink(original, async || Ok(true))
|
||||
}
|
||||
|
||||
fn symlink_file<P>(&self, original: P) -> impl Future<Output = io::Result<()>>
|
||||
where
|
||||
P: AsPathDyn,
|
||||
P: AsPath,
|
||||
{
|
||||
self.symlink(original, async || Ok(false))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,3 +7,6 @@ authors = [ "sxyazi <sxyazi@gmail.com>" ]
|
|||
description = "Yazi macros"
|
||||
homepage = "https://yazi-rs.github.io"
|
||||
repository = "https://github.com/sxyazi/yazi"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
|
|
@ -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" ],
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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" ]
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<T>(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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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" ]
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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<ByteStr<'a>>) -> PathBuf {
|
||||
pub fn join(&self, other: impl Into<Self>) -> PathBuf {
|
||||
let other = other.into();
|
||||
match self.to_path() {
|
||||
Cow::Borrowed(p) => p.join(other.to_path()),
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ pub enum Data {
|
|||
Integer(i64),
|
||||
Number(f64),
|
||||
String(SStr),
|
||||
List(Vec<Data>),
|
||||
Dict(HashMap<DataKey, Data>),
|
||||
List(Vec<Self>),
|
||||
Dict(HashMap<DataKey, Self>),
|
||||
Id(Id),
|
||||
#[serde(skip_deserializing)]
|
||||
Url(UrlBuf),
|
||||
|
|
|
|||
142
yazi-shared/src/loc/able.rs
Normal file
142
yazi-shared/src/loc/able.rs
Normal file
|
|
@ -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<Self::Owned>;
|
||||
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<Self::Strand<'p>>;
|
||||
|
||||
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<Self>
|
||||
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::Strand<'p>> { 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<Self>
|
||||
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<u8>) -> Self;
|
||||
|
||||
fn into_encoded_bytes(self) -> Vec<u8>;
|
||||
|
||||
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<u8>) -> Self {
|
||||
Self::from(unsafe { OsString::from_encoded_bytes_unchecked(bytes) })
|
||||
}
|
||||
|
||||
fn into_encoded_bytes(self) -> Vec<u8> { 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() }
|
||||
}
|
||||
|
|
@ -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<P: PathBufLike = PathBuf> {
|
||||
#[derive(Clone, Default, Eq, PartialEq)]
|
||||
pub struct LocBuf<P = PathBuf> {
|
||||
pub(super) inner: P,
|
||||
pub(super) uri: usize,
|
||||
pub(super) urn: usize,
|
||||
|
|
@ -13,7 +13,7 @@ pub struct LocBuf<P: PathBufLike = PathBuf> {
|
|||
|
||||
impl<P> Deref for LocBuf<P>
|
||||
where
|
||||
P: PathBufLike,
|
||||
P: LocBufAble,
|
||||
{
|
||||
type Target = P;
|
||||
|
||||
|
|
@ -25,37 +25,30 @@ impl AsRef<std::path::Path> for LocBuf<PathBuf> {
|
|||
fn as_ref(&self) -> &std::path::Path { self.inner.as_ref() }
|
||||
}
|
||||
|
||||
impl<T> AsPathDyn for LocBuf<T>
|
||||
impl<T> AsPath for LocBuf<T>
|
||||
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<T> AsPathDyn for &LocBuf<T>
|
||||
impl<T> AsPath for &LocBuf<T>
|
||||
where
|
||||
T: PathBufLike + AsPathDyn,
|
||||
T: LocBufAble + AsPath,
|
||||
{
|
||||
fn as_path_dyn(&self) -> PathDyn<'_> { self.inner.as_path_dyn() }
|
||||
}
|
||||
|
||||
impl<P> PartialEq for LocBuf<P>
|
||||
where
|
||||
P: PathBufLike + PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool { self.inner == other.inner }
|
||||
fn as_path(&self) -> PathDyn<'_> { self.inner.as_path() }
|
||||
}
|
||||
|
||||
impl<P> Ord for LocBuf<P>
|
||||
where
|
||||
P: PathBufLike + Ord,
|
||||
P: LocBufAble + Ord,
|
||||
{
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering { self.inner.cmp(&other.inner) }
|
||||
}
|
||||
|
||||
impl<P> PartialOrd for LocBuf<P>
|
||||
where
|
||||
P: PathBufLike + PartialOrd,
|
||||
P: LocBufAble + PartialOrd,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
self.inner.partial_cmp(&other.inner)
|
||||
|
|
@ -65,8 +58,7 @@ where
|
|||
// --- Hash
|
||||
impl<P> Hash for LocBuf<P>
|
||||
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<H: Hasher>(&self, state: &mut H) { self.as_loc().hash(state) }
|
||||
|
|
@ -74,8 +66,7 @@ where
|
|||
|
||||
impl<P> Debug for LocBuf<P>
|
||||
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<P> From<P> for LocBuf<P>
|
||||
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<T: ?Sized + AsRef<OsStr>> From<&T> for LocBuf<PathBuf> {
|
|||
|
||||
impl<P> LocBuf<P>
|
||||
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, <P::Borrowed<'b> as PathLike<'b>>::Strand<'a>>,
|
||||
S: for<'b> AsStrandView<'a, <P::Borrowed<'b> 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<Self>
|
||||
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, <P::Borrowed<'b> as PathLike<'b>>::Strand<'a>>,
|
||||
S: for<'b> AsStrandView<'a, <P::Borrowed<'b> 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<Self>
|
||||
pub fn rebase<'a, 'b>(&'a self, base: P::Borrowed<'b>) -> Self
|
||||
where
|
||||
'a: 'b,
|
||||
for<'c> <P::Borrowed<'c> as PathLike<'c>>::Owned: Into<Self>,
|
||||
for<'c> <P::Borrowed<'c> as LocAble<'c>>::Owned: Into<Self>,
|
||||
{
|
||||
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, F: FnOnce(&mut P) -> 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<P> LocBuf<P>
|
||||
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<<P::Borrowed<'_> as PathLike<'_>>::Strand<'_>> {
|
||||
self.as_loc().name()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn stem(&self) -> Option<<P::Borrowed<'_> as PathLike<'_>>::Strand<'_>> {
|
||||
self.as_loc().stem()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ext(&self) -> Option<<P::Borrowed<'_> as PathLike<'_>>::Strand<'_>> { self.as_loc().ext() }
|
||||
}
|
||||
|
||||
impl LocBuf<PathBuf> {
|
||||
|
|
@ -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::<PathBuf>::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::<PathBuf>::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::<PathBuf>::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::<PathBuf>::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::<PathBuf>::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::<PathBuf>::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(())
|
||||
|
|
|
|||
|
|
@ -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<std::path::Path> 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<H: Hasher>(&self, state: &mut H) { self.inner.hash(state) }
|
||||
}
|
||||
|
||||
impl<'p, P> From<Loc<'p, P>> for LocBuf<<P as PathLike<'p>>::Owned>
|
||||
impl<'p, P> From<Loc<'p, P>> for LocBuf<<P as LocAble<'p>>::Owned>
|
||||
where
|
||||
P: PathLike<'p>,
|
||||
<P as PathLike<'p>>::Owned: PathBufLike,
|
||||
P: LocAble<'p> + LocAbleImpl<'p>,
|
||||
<P as LocAble<'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)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
yazi_macro::mod_flat!(buf loc);
|
||||
#![allow(private_bounds)]
|
||||
|
||||
yazi_macro::mod_flat!(able buf loc);
|
||||
|
|
|
|||
|
|
@ -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<u8>;
|
||||
|
||||
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<bool, StartsWithError>
|
||||
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<u8> { 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<bool, StartsWithError>
|
||||
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<std::path::PathBuf> for PathBufDyn {
|
||||
fn from(value: std::path::PathBuf) -> Self { Self::Os(value) }
|
||||
}
|
||||
|
||||
impl From<PathDyn<'_>> for PathBufDyn {
|
||||
fn from(value: PathDyn<'_>) -> Self { value.to_owned() }
|
||||
}
|
||||
|
||||
impl TryFrom<PathBufDyn> for std::path::PathBuf {
|
||||
type Error = PathBufDynError;
|
||||
|
||||
fn try_from(value: PathBufDyn) -> Result<Self, Self::Error> { value.into_os() }
|
||||
}
|
||||
|
||||
impl PartialEq<PathDyn<'_>> for PathBufDyn {
|
||||
fn eq(&self, other: &PathDyn<'_>) -> bool { self.as_path() == *other }
|
||||
}
|
||||
|
||||
impl PartialEq<PathDyn<'_>> for &PathBufDyn {
|
||||
fn eq(&self, other: &PathDyn<'_>) -> bool { self.as_path() == *other }
|
||||
}
|
||||
|
||||
impl Equivalent<PathDyn<'_>> for PathBufDyn {
|
||||
fn equivalent(&self, key: &PathDyn<'_>) -> bool { self.as_path() == *key }
|
||||
}
|
||||
|
||||
impl PathBufDyn {
|
||||
#[inline]
|
||||
pub unsafe fn from_encoded_bytes<K>(kind: K, bytes: Vec<u8>) -> Self
|
||||
where
|
||||
K: Into<PathKind>,
|
||||
{
|
||||
match kind.into() {
|
||||
PathKind::Os => Self::Os(unsafe { OsString::from_encoded_bytes_unchecked(bytes) }.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_encoded_bytes(self) -> Vec<u8> {
|
||||
match self {
|
||||
Self::Os(p) => p.into_os_string().into_encoded_bytes(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_os(self) -> Result<std::path::PathBuf, PathBufDynError> {
|
||||
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<std::path::PathBuf>) -> Self { Self::Os(path.into()) }
|
||||
|
||||
pub fn try_extend<T>(&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<T>(&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<T>(&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<K, T>(kind: K, strand: T) -> Result<Self, StrandError>
|
||||
where
|
||||
K: Into<PathKind>,
|
||||
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<K>(kind: K, capacity: usize) -> Self
|
||||
where
|
||||
K: Into<PathKind>,
|
||||
{
|
||||
match kind.into() {
|
||||
PathKind::Os => Self::Os(std::path::PathBuf::with_capacity(capacity)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<PathCow<'_>> 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<PathBufDyn> for PathDyn<'_> {
|
||||
fn eq(&self, other: &PathBufDyn) -> bool { *self == other.borrow() }
|
||||
}
|
||||
|
||||
impl PartialEq<PathDyn<'_>> 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<PathBufDyn> 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<Self::Strand<'p>> {
|
||||
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<Self::Strand<'p>> {
|
||||
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<Self> {
|
||||
Some(match self {
|
||||
Self::Os(p) => Self::Os(p.parent()?),
|
||||
})
|
||||
}
|
||||
|
||||
fn stem(self) -> Option<Self::Strand<'p>> {
|
||||
Some(match self {
|
||||
Self::Os(p) => p.file_stem()?.into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn try_ends_with<'a, T>(self, child: T) -> Result<bool, EndsWithError>
|
||||
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<Self::Owned, JoinError>
|
||||
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<bool, StartsWithError>
|
||||
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<Self, StripPrefixError>
|
||||
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<T>(path: &'a T) -> Self
|
||||
where
|
||||
T: ?Sized + AsRef<std::path::Path>,
|
||||
{
|
||||
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<std::path::PathBuf, PathDynError> {
|
||||
match self {
|
||||
Self::Os(p) => Ok(p.to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with<T>(kind: SchemeKind, strand: &'a T) -> Result<Self, StrandError>
|
||||
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<PathKind>, 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<std::path::PathBuf> 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<PathBufDyn> for std::path::PathBuf {
|
||||
type Error = PathBufDynError;
|
||||
|
||||
fn try_from(value: PathBufDyn) -> Result<Self, Self::Error> { value.into_os() }
|
||||
}
|
||||
|
||||
impl PartialEq<PathDyn<'_>> for PathBufDyn {
|
||||
fn eq(&self, other: &PathDyn<'_>) -> bool { self.borrow() == *other }
|
||||
}
|
||||
|
||||
impl PartialEq<PathDyn<'_>> for &PathBufDyn {
|
||||
fn eq(&self, other: &PathDyn<'_>) -> bool { self.borrow() == *other }
|
||||
}
|
||||
|
||||
impl Equivalent<PathDyn<'_>> 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<u8> {
|
||||
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<bool, StartsWithError>
|
||||
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<std::path::PathBuf>) -> Self { Self::Os(path.into()) }
|
||||
|
||||
#[inline]
|
||||
pub fn into_os(self) -> Result<std::path::PathBuf, PathBufDynError> {
|
||||
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<T>(kind: SchemeKind, strand: T) -> Result<Self, StrandError>
|
||||
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<T>(&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<T>(&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<PathKind>, bytes: Vec<u8>) -> Self {
|
||||
match kind.into() {
|
||||
PathKind::Os => Self::Os(unsafe { std::path::PathBuf::from_encoded_bytes(bytes) }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ pub enum JoinError {
|
|||
}
|
||||
|
||||
impl From<JoinError> 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<PathDynError> 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<SetNameError> 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<StrandError> 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")]
|
||||
|
|
|
|||
96
yazi-shared/src/path/like.rs
Normal file
96
yazi-shared/src/path/like.rs
Normal file
|
|
@ -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<Strand<'_>> { 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<Strand<'_>> { self.as_path().name() }
|
||||
|
||||
fn parent(&self) -> Option<PathDyn<'_>> { self.as_path().parent() }
|
||||
|
||||
fn rsplit_pred<T>(&self, pred: T) -> Option<(PathDyn<'_>, PathDyn<'_>)>
|
||||
where
|
||||
T: Utf8BytePredictor,
|
||||
{
|
||||
self.as_path().rsplit_pred(pred)
|
||||
}
|
||||
|
||||
fn stem(&self) -> Option<Strand<'_>> { self.as_path().stem() }
|
||||
|
||||
fn to_os_owned(&self) -> Result<std::path::PathBuf, PathDynError> { 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<T>(&self, child: T) -> Result<bool, EndsWithError>
|
||||
where
|
||||
T: AsStrand,
|
||||
{
|
||||
self.as_path().try_ends_with(child)
|
||||
}
|
||||
|
||||
fn try_join<T>(&self, path: T) -> Result<PathBufDyn, JoinError>
|
||||
where
|
||||
T: AsStrand,
|
||||
{
|
||||
self.as_path().try_join(path)
|
||||
}
|
||||
|
||||
fn try_rsplit_seq<T>(&self, pat: T) -> Result<(PathDyn<'_>, PathDyn<'_>), RsplitOnceError>
|
||||
where
|
||||
T: AsStrand,
|
||||
{
|
||||
self.as_path().try_rsplit_seq(pat)
|
||||
}
|
||||
|
||||
fn try_starts_with<T>(&self, base: T) -> Result<bool, StartsWithError>
|
||||
where
|
||||
T: AsStrand,
|
||||
{
|
||||
self.as_path().try_starts_with(base)
|
||||
}
|
||||
|
||||
fn try_strip_prefix<T>(&self, base: T) -> Result<PathDyn<'_>, StripPrefixError>
|
||||
where
|
||||
T: AsStrand,
|
||||
{
|
||||
self.as_path().try_strip_prefix(base)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> From<&P> for PathBufDyn
|
||||
where
|
||||
P: PathLike,
|
||||
{
|
||||
fn from(value: &P) -> Self { value.to_owned() }
|
||||
}
|
||||
|
||||
impl PathLike for PathBufDyn {}
|
||||
impl PathLike for PathCow<'_> {}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<Self::Owned>;
|
||||
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<PathBufDyn> for PathDyn<'_> {
|
||||
fn eq(&self, other: &PathBufDyn) -> bool { *self == other.as_path() }
|
||||
}
|
||||
|
||||
fn display(self) -> Self::Display<'p>;
|
||||
impl PartialEq<PathDyn<'_>> 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<Self::Strand<'p>>;
|
||||
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<PathBufDyn> 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<Strand<'p>> {
|
||||
Some(match self {
|
||||
Self::Os(p) => p.extension()?.into(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn from_encoded_bytes<K>(kind: K, bytes: &'p [u8]) -> Self
|
||||
where
|
||||
K: Into<PathKind>,
|
||||
{
|
||||
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<Self::Strand<'p>>;
|
||||
|
||||
fn owned(self) -> Self::Owned;
|
||||
|
||||
fn parent(self) -> Option<Self>;
|
||||
|
||||
fn rsplit_pred<T>(self, pred: T) -> Option<(Self, Self)>
|
||||
where
|
||||
T: Utf8BytePredictor;
|
||||
|
||||
fn stem(self) -> Option<Self::Strand<'p>>;
|
||||
|
||||
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<bool, EndsWithError>
|
||||
where
|
||||
T: AsStrandView<'a, Self::Strand<'a>>;
|
||||
|
||||
fn try_join<'a, T>(self, path: T) -> Result<Self::Owned, JoinError>
|
||||
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<bool, StartsWithError>
|
||||
where
|
||||
T: AsStrandView<'a, Self::Strand<'a>>;
|
||||
|
||||
fn try_strip_prefix<'a, T>(self, base: T) -> Result<Self, StripPrefixError>
|
||||
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::Strand<'p>> { 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::Strand<'p>> { self.file_name() }
|
||||
|
||||
fn owned(self) -> Self::Owned { self.to_path_buf() }
|
||||
|
||||
fn parent(self) -> Option<Self> { self.parent() }
|
||||
|
||||
fn stem(self) -> Option<Self::Strand<'p>> { self.file_stem() }
|
||||
|
||||
fn try_ends_with<'a, T>(self, child: T) -> Result<bool, EndsWithError>
|
||||
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<Self::Owned, JoinError>
|
||||
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<Strand<'p>> {
|
||||
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<T>(path: &'p T) -> Self
|
||||
where
|
||||
T: ?Sized + AsRef<std::path::Path>,
|
||||
{
|
||||
Self::Os(path.as_ref())
|
||||
}
|
||||
|
||||
pub fn parent(self) -> Option<Self> {
|
||||
Some(match self {
|
||||
Self::Os(p) => Self::Os(p.parent()?),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn rsplit_pred<T>(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<Strand<'p>> {
|
||||
Some(match self {
|
||||
Self::Os(p) => p.file_stem()?.into(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_os_owned(self) -> Result<std::path::PathBuf, PathDynError> {
|
||||
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<T>(self, child: T) -> Result<bool, EndsWithError>
|
||||
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<T>(self, path: T) -> Result<PathBufDyn, JoinError>
|
||||
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<T>(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<bool, StartsWithError>
|
||||
pub fn try_starts_with<T>(self, base: T) -> Result<bool, StartsWithError>
|
||||
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<Self, StripPrefixError>
|
||||
pub fn try_strip_prefix<T>(self, base: T) -> Result<Self, StripPrefixError>
|
||||
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<K, T>(kind: K, strand: &'p T) -> Result<Self, StrandError>
|
||||
where
|
||||
K: Into<PathKind>,
|
||||
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<P> for PathBufDyn
|
||||
where
|
||||
P: PathLike<'a>,
|
||||
{
|
||||
fn from(value: P) -> Self { value.to_buf_dyn() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<u8>) -> Self;
|
||||
}
|
||||
|
||||
impl PathBufUnsafeExt for std::path::PathBuf {
|
||||
unsafe fn from_encoded_bytes(bytes: Vec<u8>) -> Self {
|
||||
Self::from(unsafe { OsString::from_encoded_bytes_unchecked(bytes) })
|
||||
}
|
||||
}
|
||||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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<usize>,
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
85
yazi-shared/src/strand/buf.rs
Normal file
85
yazi-shared/src/strand/buf.rs
Normal file
|
|
@ -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<u8>),
|
||||
}
|
||||
|
||||
impl Default for StrandBuf {
|
||||
fn default() -> Self { Self::Utf8(String::new()) }
|
||||
}
|
||||
|
||||
impl From<OsString> for StrandBuf {
|
||||
fn from(value: OsString) -> Self { Self::Os(value) }
|
||||
}
|
||||
|
||||
impl From<String> for StrandBuf {
|
||||
fn from(value: String) -> Self { Self::Utf8(value) }
|
||||
}
|
||||
|
||||
impl From<PathDyn<'_>> for StrandBuf {
|
||||
fn from(value: PathDyn) -> Self {
|
||||
match value {
|
||||
PathDyn::Os(p) => Self::Os(p.as_os_str().to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Strand<'_>> 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<StrandKind>, bytes: Vec<u8>) -> 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<u8> {
|
||||
match self {
|
||||
Self::Os(s) => s.into_encoded_bytes(),
|
||||
Self::Utf8(s) => s.into_bytes(),
|
||||
Self::Bytes(b) => b,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_push<T>(&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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<u8> {
|
||||
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::<OsStr>::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() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Strand<'_>> for StrandCow<'_> {
|
|||
}
|
||||
|
||||
impl<'a> StrandCow<'a> {
|
||||
pub fn with<T>(kind: SchemeKind, bytes: T) -> Result<Self>
|
||||
where
|
||||
T: Into<Cow<'a, [u8]>>,
|
||||
{
|
||||
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<Cow<'a, [u8]>>) -> Result<Self> {
|
||||
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<T>(kind: SchemeKind, bytes: T) -> Result<Self>
|
||||
where
|
||||
T: Into<Cow<'a, [u8]>>,
|
||||
{
|
||||
match kind {
|
||||
SchemeKind::Regular | SchemeKind::Search | SchemeKind::Archive => Self::from_os_bytes(bytes),
|
||||
SchemeKind::Sftp => Self::from_os_bytes(bytes), // FIXME
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<StrandKind>, 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<u8>),
|
||||
}
|
||||
pub fn is_empty(self) -> bool { self.encoded_bytes().is_empty() }
|
||||
|
||||
impl Default for StrandBuf {
|
||||
fn default() -> Self { Self::Utf8(String::new()) }
|
||||
}
|
||||
|
||||
impl From<OsString> for StrandBuf {
|
||||
fn from(value: OsString) -> Self { Self::Os(value) }
|
||||
}
|
||||
|
||||
impl From<String> for StrandBuf {
|
||||
fn from(value: String) -> Self { Self::Utf8(value) }
|
||||
}
|
||||
|
||||
impl From<PathDyn<'_>> for StrandBuf {
|
||||
fn from(value: PathDyn) -> Self {
|
||||
match value {
|
||||
PathDyn::Os(p) => Self::Os(p.as_os_str().to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Strand<'_>> 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<T>(&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<StrandKind>, bytes: Vec<u8>) -> 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()) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,5 +20,5 @@ impl From<PathDynError> for StrandError {
|
|||
}
|
||||
|
||||
impl From<StrandError> for std::io::Error {
|
||||
fn from(err: StrandError) -> Self { std::io::Error::other(err) }
|
||||
fn from(err: StrandError) -> Self { Self::other(err) }
|
||||
}
|
||||
|
|
|
|||
47
yazi-shared/src/strand/like.rs
Normal file
47
yazi-shared/src/strand/like.rs
Normal file
|
|
@ -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<S> From<&S> for StrandBuf
|
||||
where
|
||||
S: StrandLike,
|
||||
{
|
||||
fn from(value: &S) -> Self { value.to_owned() }
|
||||
}
|
||||
|
||||
impl StrandLike for StrandBuf {}
|
||||
impl StrandLike for StrandCow<'_> {}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<u8>;
|
||||
|
||||
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<u8>;
|
||||
|
||||
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<u8> {
|
||||
type Borrowed<'a> = &'a [u8];
|
||||
|
||||
fn borrow(&self) -> Self::Borrowed<'_> { self.as_slice() }
|
||||
|
||||
fn into_encoded_bytes(self) -> Vec<u8> { self }
|
||||
}
|
||||
|
||||
impl StrandBufLike for String {
|
||||
type Borrowed<'a> = &'a str;
|
||||
|
||||
fn borrow(&self) -> Self::Borrowed<'_> { self.as_str() }
|
||||
|
||||
fn into_encoded_bytes(self) -> Vec<u8> { 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<u8> { 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<u8> {
|
||||
match self {
|
||||
Self::Os(s) => s.into_encoded_bytes(),
|
||||
Self::Utf8(s) => s.into_bytes(),
|
||||
Self::Bytes(b) => b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Url<'_>> 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<Self> {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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<UrlBuf, JoinError> {
|
||||
fn try_join(&self, path: impl AsStrand) -> Result<UrlBuf, JoinError> {
|
||||
self.as_url().try_join(path)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<UrlBuf, JoinError> {
|
||||
let joined = self.loc().try_join(&path)?;
|
||||
pub fn try_join(self, path: impl AsStrand) -> Result<UrlBuf, JoinError> {
|
||||
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<Strand<'a>> {
|
||||
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<Strand<'a>> {
|
||||
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<Strand<'a>> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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<Resul
|
|||
});
|
||||
|
||||
tokio::spawn({
|
||||
let (prog_tx, to) = (prog_tx.to_owned(), to.to_owned());
|
||||
let (prog_tx, to) = (prog_tx.clone(), to.to_owned());
|
||||
async move {
|
||||
let mut last = 0;
|
||||
let mut done = None;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use yazi_fs::FilesOp;
|
||||
use yazi_shared::{path::PathLike, url::{UrlBuf, UrlLike}};
|
||||
use yazi_shared::url::{UrlBuf, UrlLike};
|
||||
|
||||
use crate::maybe_exists;
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ impl VfsFilesOp for FilesOp {
|
|||
} else if maybe_exists(cwd).await {
|
||||
Self::IOErr(cwd.clone(), err).emit();
|
||||
} else if let Some((p, n)) = cwd.pair() {
|
||||
Self::Deleting(p.into(), [n.owned()].into()).emit();
|
||||
Self::Deleting(p.into(), [n.into()].into()).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::io;
|
|||
|
||||
use tokio::io::{AsyncWriteExt, BufReader, BufWriter};
|
||||
use yazi_fs::{cha::Cha, provider::{Attrs, Provider, local::Local}};
|
||||
use yazi_shared::{path::{AsPathDyn, PathBufDyn}, url::{AsUrl, UrlBuf, UrlCow}};
|
||||
use yazi_shared::{path::{AsPath, PathBufDyn}, url::{AsUrl, UrlBuf, UrlCow}};
|
||||
|
||||
use super::{Providers, ReadDir, RwFile};
|
||||
|
||||
|
|
@ -199,7 +199,7 @@ where
|
|||
|
||||
pub async fn symlink_dir<P, U>(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<P, U>(original: P, link: U) -> io::Result<()>
|
||||
where
|
||||
P: AsPathDyn,
|
||||
P: AsPath,
|
||||
U: AsUrl,
|
||||
{
|
||||
Providers::new(link.as_url()).await?.symlink_file(original).await
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue